## [1] "!! low !! The experiment investigate the effects of two disturbance levels: low and high. To make it easier to interpet, we showcase only one of the two disturbance levels. In this document we showcase only the low disturbance)"

Design

Ecosystem size is a key factor driving biodiversity and ecosystem function. Larger ecosystems contain more species and can be hubs of dispersal and resource flows in networks of multiple ecosystems. However, whether and how ecosystem size and resource flows interact to affect biodiversity and ecosystem function has been largely overlooked. Here, we investigated how ecosystem size asymmetry affects biodiversity and function of two-ecosystem meta-ecosystems connected through flows of non-living resources. We conducted microcosm experiments, mimicking resource flows between ecosystems of different sizes, yet otherwise being identical. We found that meta-ecosystems with asymmetric ecosystem sizes had higher β-diversity but lower α-diversity and ecosystem function (total biomass) than their unconnected counterparts, while such an effect was not found for meta-ecosystems of identical ecosystem sizes. Our work demonstrates of how cross-ecosystem dynamics modulated by differences in ecosystem sizes affect biodiversity and function, with a direct implication for conservation and management of connected ecosystems.

Parameters

Parameters for R markdown and the general running of the code.

start_time = Sys.time()
knitr::opts_chunk$set(message = FALSE,
                      cache = FALSE,
                      autodep = FALSE)
recompute_lengthy_analyses = FALSE 
plot_model_residuals_metaecos = FALSE

Parameters related to resource flows.

disturbance_levels = c("low", "high")
n_disturbance_levels = length(disturbance_levels)

resource_flow_days = c(5, 9, 13, 17, 21, 25)
first_resource_flow = resource_flow_days[1]

Parameters related to sampling.

total_frames = 125
volume_recorded_μl = 34.4
time_points = 0:7
time_points_without_t0 = 1:7
time_point_names = c("t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7")
sampling_days = c(0, 4, 8, 12, 16, 20, 24, 28)
first_time_point = 0
last_time_point = length(sampling_days) - 1
n_time_points = last_time_point + 1
nr_videos = c(12, 1, 1, 1, 1, 1, 2, 2) #Videos taken for each time point for each culture. At t0 we took 12 videos of the large bottle from which we started the  cultures. Write why 2 at the end. 

videos_taken = data.frame(time_point = 0 : 7,
                          nr_videos = c(12, 1, 1, 1, 1, 1, 2, 2))

n_videos_taken_t0 = nr_videos[1]

time_point_day = data.frame(time_point = first_time_point:last_time_point,
                            day = sampling_days,
                            video_replicates = nr_videos)

videos_to_take_off = data.frame(culture_ID = NA,
                                time_point = NA,
                                file = NA) %>%
                     add_row(culture_ID = 137-110, 
                             time_point = 7, 
                             file = 137) %>%
                     slice(-1)

n_cultures = 110
total_number_of_video_rows = sum(nr_videos * n_cultures)

Parameters related to protists.

protist_species = c("Ble", "Cep", "Col", "Eug", "Eup", "Lox", "Pau", "Pca", "Spi", "Spi_te", "Tet")
protist_species_indiv_per_volume = paste0(protist_species, "_indiv_per_volume")
protist_species_indiv_per_ml = paste0(protist_species, "_indiv_per_ml")
protist_species_dominance = paste0(protist_species_indiv_per_ml, "_dominance")
protist_species_total = paste0(protist_species, "_tot_indiv")
n_protist_species = length(protist_species)
first_protist = protist_species[1]
last_protist = protist_species[n_protist_species]
species_IDD_with_13_threshold = c("Col", "Eug", "Eup", "Lox", "Pau", "Pca", "Spi_te", "Tet")
species_IDD_with_13_threshold_indiv_per_volume = paste0(species_IDD_with_13_threshold, "_indiv_per_volume")
species_IDD_with_40_threshold = c("Ble", "Cep", "Spi")
species_IDD_with_40_threshold_indiv_per_volume = paste0(species_IDD_with_40_threshold, "_indiv_per_volume")

Parameters related to ecosystems.

ecosystems_to_take_off = 60 #Culture ID = 60 as it was spilled (small unconnected, high disturbance, system nr = 40)
ecosystems_info = read.csv(here("2_data", "ecosystems_info.csv"), header = TRUE)

columns_ecosystems = c("time_point",
                       "day",
                       "culture_ID",
                       "system_nr",
                       "disturbance",
                       "ecosystem_type",
                       "connection",
                       "ecosystem_size",
                       "ecosystem_size_ml",
                       "metaecosystem",
                       "metaecosystem_type")
columns_treatments = columns_ecosystems[!columns_ecosystems %in% c("system_nr", "culture_ID")]

variables_ecosystems = c("bioarea_mm2_per_ml",
                         "bioarea_tot_mm2",
                         "indiv_per_ml",
                         "indiv_tot",
                         "species_richness",
                         "shannon",
                         "simpson",
                         "inv_simpson",
                         "evenness_pielou",
                         "median_body_area_µm2",
                         paste0(protist_species, "_indiv_per_ml"),
                         paste0(protist_species, "_tot_indiv"),
                         paste0(protist_species_indiv_per_ml, "_dominance"))
baseline_columns = paste0("baseline_", variables_ecosystems)

ecosystem_types_ordered = c("Small connected to large",
                        "Small connected to small",
                        "Small unconnected",
                        "Medium connected to medium",
                        "Medium unconnected",
                        "Large connected to small",
                        "Large connected to large",
                        "Large unconnected")

treatments_and_controls = data.frame(treatment = c("Small connected to small",
                                                   "Small connected to large",
                                                   "Medium connected to medium",
                                                   "Large connected to large",
                                                   "Large connected to small"),
                                     control = c("Small unconnected",
                                                 "Small unconnected",
                                                 "Medium unconnected",
                                                 "Large unconnected",
                                                 "Large unconnected"))

n_treatments = length(unique(treatments_and_controls$treatment))
n_controls = length(unique(treatments_and_controls$control))
n_replicates = 5
n_ecosystem_types = 8

Parameters related to size classes.

n_size_classes = 12
columns_classes = c(columns_ecosystems,
                    "size_class_n",
                    "mean_class_area_µm2")

Parameters related to meta-ecosystems.

metaecosystems_to_take_off = ecosystems_info %>%
  filter(culture_ID %in% ecosystems_to_take_off) %>%
  pull(system_nr) %>%
  unique

system_nr_metaecosystems = ecosystems_info %>%
  filter(metaecosystem == "yes") %>%
  pull(system_nr) %>%
  unique

n_metaecosystems = length(system_nr_metaecosystems)

variables_metaecos = c(
  "total_metaecosystem_bioarea_mm2",
  "jaccard_index",
  "bray_curtis",
  "beta_spatial_turnover",
  "beta_nestedness",
  "beta_total",
  "metaecosystem_richness")

metaecosystem_types_ordered = c(
      "Small-Small meta-ecosystem",
      "Medium-Medium meta-ecosystem",
      "Medium-Medium unconnected",
      "Large-Large meta-ecosystem",
      "Small-Large meta-ecosystem",
      "Small-Large unconnected")

Name of the axes per response variable.

axis_names = data.frame(variable = NA,
                        axis_name= NA) %>%
  add_row(variable = "day", axis_name = "Time (day)") %>%
  add_row(variable = "ecosystem_size_ml", axis_name = "Patch size (ml)") %>%
  add_row(variable = "log_size_class", axis_name = "Log size (μm2)") %>%
  add_row(variable = "class_indiv_per_µl", axis_name = "Density (ind/ml)") %>%
  add_row(variable = "bioarea_mm2_per_ml", axis_name = "Biomass (mm2/ml)") %>%
  add_row(variable = "bioarea_mm2_per_ml_d", axis_name = "Bioamass ES") %>%
  add_row(variable = "bioarea_tot", axis_name = "Total Biomass (mm2)") %>%
  add_row(variable = "total_metaecosystem_bioarea_mm2", axis_name = "Total Biomass (mm2)") %>%
  add_row(variable = "species_richness", axis_name = "Species Richness") %>%
  add_row(variable = "species_richness_d", axis_name = "Species Richness ES") %>%
  add_row(variable = "mean_richness", axis_name = "Mean α-Diversity (Shannon)") %>%
  add_row(variable = "mean_shannon", axis_name = "Mean α-Diversity (Shannon)") %>%
  add_row(variable = "shannon", axis_name = "Biodiversity (Shannon)") %>%
  add_row(variable = "shannon_d", axis_name = "Biodiversity ES (Shannon ES)") %>%
  add_row(variable = "bray_curtis", axis_name = "β-Diversity (Bray-Curtis)") %>%
  add_row(variable = "beta_spatial_turnover", axis_name = "Turn over (Simpson pair-wise dissimilarity)") %>%
  add_row(variable = "beta_nestedness", axis_name = "Nestedness (nestedness-fraction of Sorensen)") %>%
  add_row(variable = "beta_total", axis_name = "Tot β-Diversity (Sorensen)") %>%
  add_row(variable = "metaecosystem_richness", axis_name = "γ-Diversity (Species Richness)") %>%
  add_row(variable = "indiv_per_ml", axis_name = "Abundance (ind/ml)") %>%
  add_row(variable = "indiv_per_ml_d", axis_name = "Abundance ES") %>%
  add_row(variable = "median_body_area_µm2", axis_name = "Median Body Size (µm²)") %>%
  add_row(variable = "median_body_area_µm2_d", axis_name = "Median Body Size ES") %>%
  add_row(variable = "Ble_indiv_per_ml", axis_name = "Ble Density (ind/ml)") %>% 
  add_row(variable = "Cep_indiv_per_ml", axis_name = "Cep Density (ind/ml)") %>%
  add_row(variable = "Col_indiv_per_ml", axis_name = "Col Density (ind/ml)") %>%
  add_row(variable = "Eug_indiv_per_ml", axis_name = "Eug Density (ind/ml)") %>%
  add_row(variable = "Eup_indiv_per_ml", axis_name = "Eup Density (ind/ml)") %>%
  add_row(variable = "Lox_indiv_per_ml", axis_name = "Lox Density (ind/ml)") %>%
  add_row(variable = "Pau_indiv_per_ml", axis_name = "Pau Density (ind/ml)") %>%
  add_row(variable = "Pca_indiv_per_ml", axis_name = "Pca Density (ind/ml)") %>%
  add_row(variable = "Spi_indiv_per_ml", axis_name = "Spi Density (ind/ml)") %>%
  add_row(variable = "Spi_te_indiv_per_ml", axis_name = "Spi te Density (ind/ml)") %>%
  add_row(variable = "Tet_indiv_per_ml", axis_name = "Tet Density (ind/ml)") %>%
  add_row(variable = "auto_hetero_ratio", axis_name = "Photosynthetisers-Heterotrops Ratio") %>%
  add_row(variable = "Ble_indiv_per_ml_d", axis_name = "Ble Density ES") %>%
  add_row(variable = "Cep_indiv_per_ml_d", axis_name = "Cep Density ES") %>%
  add_row(variable = "Col_indiv_per_ml_d", axis_name = "Col Density ES") %>%
  add_row(variable = "Eug_indiv_per_ml_d", axis_name = "Eug Density ES") %>%
  add_row(variable = "Eup_indiv_per_ml_d", axis_name = "Eup Density ES") %>%
  add_row(variable = "Lox_indiv_per_ml_d", axis_name = "Lox Density ES") %>%
  add_row(variable = "Pau_indiv_per_ml_d", axis_name = "Pau Density ES") %>%
  add_row(variable = "Pca_indiv_per_ml_d", axis_name = "Pca Density ES") %>%
  add_row(variable = "Spi_indiv_per_ml_d", axis_name = "Spi Density ES") %>%
  add_row(variable = "Spi_te_indiv_per_ml_d", axis_name = "Spi te Density ES") %>%
  add_row(variable = "Tet_indiv_per_ml_d", axis_name = "Tet Density ES") %>%
  add_row(variable = "Ble_indiv_per_ml_dominance", axis_name = "Ble Dominance (%)") %>%
  add_row(variable = "Cep_indiv_per_ml_dominance", axis_name = "Cep Dominance (%)") %>%
  add_row(variable = "Col_indiv_per_ml_dominance", axis_name = "Col Dominance (%)") %>%
  add_row(variable = "Eug_indiv_per_ml_dominance", axis_name = "Eug Dominance (%)") %>%
  add_row(variable = "Eup_indiv_per_ml_dominance", axis_name = "Eup Dominance (%)") %>%
  add_row(variable = "Lox_indiv_per_ml_dominance", axis_name = "Lox Dominance (%)") %>%
  add_row(variable = "Pau_indiv_per_ml_dominance", axis_name = "Pau Dominance (%)") %>%
  add_row(variable = "Pca_indiv_per_ml_dominance", axis_name = "Pca Dominance (%)") %>%
  add_row(variable = "Spi_indiv_per_ml_dominance", axis_name = "Spi Dominance (%)") %>%
  add_row(variable = "Spi_te_indiv_per_ml_dominance", axis_name = "Spi te Dominance (%)") %>%
  add_row(variable = "Tet_indiv_per_ml_dominance", axis_name = "Tet Dominance (%)") %>%
  add_row(variable = "Ble_indiv_per_ml_dominance_d", axis_name = "Ble Dominance ES") %>%
  add_row(variable = "Cep_indiv_per_ml_dominance_d", axis_name = "Cep Dominance ES") %>%
  add_row(variable = "Col_indiv_per_ml_dominance_d", axis_name = "Col Dominance ES") %>%
  add_row(variable = "Eug_indiv_per_ml_dominance_d", axis_name = "Eug Dominance ES") %>%
  add_row(variable = "Eup_indiv_per_ml_dominance_d", axis_name = "Eup Dominance ES") %>%
  add_row(variable = "Lox_indiv_per_ml_dominance_d", axis_name = "Lox Dominance ES") %>%
  add_row(variable = "Pau_indiv_per_ml_dominance_d", axis_name = "Pau Dominance ES") %>%
  add_row(variable = "Pca_indiv_per_ml_dominance_d", axis_name = "Pca Dominance ES") %>%
  add_row(variable = "Sp_indiv_per_mli_dominance_d", axis_name = "Spi Dominance ES") %>%
  add_row(variable = "Spi_te_indiv_per_ml_dominance_d", axis_name = "Spi te Dominance ES") %>%
  add_row(variable = "Tet_indiv_per_ml_dominance_d", axis_name = "Tet Dominance ES") %>%
  add_row(variable = "dominance", axis_name = "Dominance (%)") %>%
  add_row(variable = "log_abundance", axis_name = "Log Abundance + 1 (ind/mm²)") %>%
  add_row(variable = "abundance_hedges_d", axis_name = "Density ES") %>%
  add_row(variable = "beta_diversity_from_unconnected", axis_name = "Divergence from unconnected") %>%
  add_row(variable = "beta_diversity_from_previous_time", axis_name = "Temporal Divergence") %>%
  add_row(variable = "beta_diversity_from_previous_time_d", axis_name = "Temporal Divergence ES") %>%
  add_row(variable = "evenness_pielou", axis_name = "Evenness") %>%
  add_row(variable = "evenness_pielou_d", axis_name = "Evenness ES") %>%
  slice(-1)

Colour and line type per ecosystem/meta-ecosystem type.

treatment_colours = c("Small" = "#feb24c",
                      "Medium" = "#1b7837",
                      "Large" = "#3182bd",
                      "Small-Small" = "#fc9272",
                      "Large-Large" = "#67000d",
                      "Small-Large" = "#762a83",
                      "Medium-Medium" = "#1b7837",
                      "symmetric" = "#1b7837",
                      "asymmetric" = "#762a83")

treatment_linetype = c("connected to small" = "solid",
                       "connected to medium" = "dashed",
                       "connected to large" = "longdash",
                       "connected" = "solid",
                       "unconnected" = "dotted")

Parameters for plotting.

figures_height_rmd_output = 7

legend_position = "top"
legend_width_cm = 2
size_legend = 12
size_x_axis = 13
size_y_axis = size_x_axis
boxplot_width = 2
dodging = 0.5 
width_errorbar = 0.2
dodging_error_bar = 0.5

treatment_lines_linewidth = 1
treatment_points_size = 2.5

resource_flow_line_type = "solid"
resource_flow_line_colour = "#d9d9d9"
resource_flow_line_width = 0.3

zero_line_colour = "grey"
zero_line_line_type = "dotted"
zero_line_line_width = 0.5
zero_line_ES_line_type = "dotted"
zero_line_ES_colour = "grey"
zero_line_ES_line_width = 1

ggarrange_margin_top = 0
ggarrange_margin_bottom = 0
ggarrange_margin_left = 0
ggarrange_margin_right = 0

paper_width = 17.3
paper_height = 20
paper_units = "cm"
paper_res = 600
paper_y_axis_size = 9
paper_labels_size = 9

presentation_figure_size = 15
presentation_figure_width = 30
presentation_figure_height = 22
presentation_legend_size = 20
presentation_x_axis_size = 22
presentation_y_axis_size = presentation_x_axis_size
presentation_axes_size = 12
presentation_treatment_points_size = 5
presentation_treatment_linewidth = 2
presentation_figure_units = "cm"
presentation_figure_res = 600

grey_background_xmin = -Inf
grey_background_xmax = 7.5
grey_background_ymin = -Inf
grey_background_ymax = Inf
grey_background_fill = "#f0f0f0"
grey_background_alpha = 0.03
grey_background_color = "transparent"

Parameters for modelling.

time_point_of_baselines = 1
time_points_with_water_addtion = 3:7
time_points_model = time_points_with_water_addtion

optimizer_input = 'Nelder_Mead'
method_input = ''

Data

Ecosystems information (ecosystems_info)

We start by importing the information about the 110 ecosystems of the experiment.

ecosystems_info = read.csv(here("2_data", "ecosystems_info.csv"), header = TRUE)

Individuals (ds_individuals)

In this dataset (ds_individuals) each row represents an individual at a time point.

# Import the individual data of t0. We considered cultures to be all the same at the beginning (t0). Because of this reason, we filmed only the bottles from which cultures were assembled. Because we want to plot also t0 for the different treatments, we want to assign the video of bottles to all cultures at t0.

ds_individuals_t0_not_elongated = read.csv(here("2_data", 
                                                "individuals_13_threshold", 
                                                "t0.csv")) %>%
  mutate(time_point =  as.numeric(str_extract(time_point, "\\d+")),
         day = 0,
         file =  as.numeric(str_extract(file, "\\d+")),
         video_replicate = file) %>%
  select(time_point,
         day,
         video_replicate,
         file,
         id,
         N_frames,
         mean_area)

ds_individuals_t0_elongated = ds_individuals_t0_not_elongated %>%
  map_dfr(.x = 1 : nrow(ecosystems_info),
          .f = ~ ds_individuals_t0_not_elongated) %>% 
  arrange(id) %>% #Id refers to an individual
  mutate(culture_ID = rep(1 : nrow(ecosystems_info),
                          times = nrow(ds_individuals_t0_not_elongated))) %>%
  select(time_point,
         day,
         video_replicate,
         file,
         culture_ID,
         id,
         N_frames,
         mean_area)

expect_equal(nrow(ds_individuals_t0_not_elongated) * nrow(ecosystems_info),
             nrow(ds_individuals_t0_elongated))
#Import t1-t4

ds_individuals_t1_to_t4 = NULL
  
for (time_point_i in time_points_without_t0) {
  
  ds_individuals_t1_to_t4[[time_point_i]] = read.csv(here("2_data", 
                                                          "individuals_13_threshold", 
                                                          paste0("t", 
                                                                 time_point_i, 
                                                                 ".csv"))) %>%
    mutate(time_point =  as.numeric(str_extract(time_point, "\\d+")),
           day = time_point_day$day[time_point_day$time_point == time_point_i],
           file =  as.numeric(str_extract(file, "\\d+")),
           video_replicate = ceiling(file/n_cultures)) #Until 110 video replicate = 1, then 2
  }

ds_individuals_t1_to_t4 = ds_individuals_t1_to_t4 %>%
  bind_rows() %>%
  select(time_point,
         day,
         video_replicate,
         file,
         culture_ID,
         id,
         N_frames,
         mean_area)
# Bind t0 with t1-t4

ds_individuals = rbind(ds_individuals_t0_elongated,
                       ds_individuals_t1_to_t4) %>%
  left_join(ecosystems_info,
            by = "culture_ID") 
# Rename and select columns

ds_individuals = ds_individuals %>% 
  rename(ecosystem_size = patch_size,
         ecosystem_size_volume = patch_size_volume) %>%
  select(
    disturbance,
    disturbance_volume,
    time_point,
    day,
    video_replicate,
    culture_ID,
    system_nr,
    file,
    eco_metaeco_type,
    ecosystem_size,
    ecosystem_size_volume,
    metaecosystem,
    metaecosystem_type,
    mean_area,
    N_frames
  ) %>%
  rename(ecosystem_size_ml = ecosystem_size_volume,
         ecosystem_type = eco_metaeco_type,
         body_area_µm2 = mean_area)
# Rename and reorder levels

ds_individuals <- ds_individuals %>%
  mutate(ecosystem_type = case_when(ecosystem_type == "S" ~ "Small unconnected",
                                ecosystem_type == "M" ~ "Medium unconnected",
                                ecosystem_type == "L" ~ "Large unconnected",
                                ecosystem_type == "S (S_S)" ~ "Small connected to small",
                                ecosystem_type == "S (S_L)" ~ "Small connected to large",
                                ecosystem_type == "M (M_M)" ~ "Medium connected to medium",
                                ecosystem_type == "L (S_L)" ~ "Large connected to small",
                                ecosystem_type == "L (L_L)" ~ "Large connected to large",
                                TRUE ~ ecosystem_type),
         ecosystem_type = factor(ecosystem_type,
                             levels = ecosystem_types_ordered))

ds_individuals <- ds_individuals %>%
  mutate(ecosystem_size = case_when(ecosystem_size == "S" ~ "Small",
                                ecosystem_size == "M" ~ "Medium",
                                ecosystem_size == "L" ~ "Large",
                                TRUE ~ ecosystem_type),
         ecosystem_size = factor(ecosystem_size,
                             levels = "Small", 
                                      "Medium", 
                                      "Large"))

ds_individuals <- ds_individuals %>%
  mutate(size_connected_ecosystem = case_when(ecosystem_type == "Small connected to small" ~ "Small",
                                          ecosystem_type == "Small connected to large" ~ "Large",
                                          ecosystem_type == "Medium connected to medium" ~ "Medium",
                                          ecosystem_type == "Large connected to large" ~ "Large",
                                          ecosystem_type == "Large connected to small" ~ "Small",
                                          TRUE ~ NA_character_))
# Take off problematic videos

ds_individuals_before_taking_off_videos = ds_individuals

ds_individuals = ds_individuals %>%
  filter(!(time_point %in% videos_to_take_off$time_point & file %in% videos_to_take_off$file))

diff = setdiff(ds_individuals_before_taking_off_videos, ds_individuals)

expect_equal(nrow(videos_to_take_off),
             nrow(expand.grid(diff$culture_ID, diff$time_point, diff$file) %>% unique()))
# Take off problematic cultures 

ds_individuals_before_taking_off_cultures = ds_individuals

ds_individuals = ds_individuals %>%
  filter(!culture_ID %in% ecosystems_to_take_off)

expect_equal(setdiff(ds_individuals_before_taking_off_cultures, 
                     ds_individuals) %>% 
               pull(culture_ID) %>% 
               unique(),
             ecosystems_to_take_off)

Patches (ds_ecosystems)

In this dataset (ds_ecosystems) each row represents a ecosystem at a time point. I use the data from the 40 threshold analysis for Ble, Cep, Spi and the data from the 13 threshold analysis for all the other protists (Col, Eup, Lox, Pau, Pca, Spi te, Tet).

# Import & bind t0 datasets.

ds_ecosystems_t0 = read.csv(here("2_data", 
                              "ecosystems_13_threshold", 
                              "t0.csv")) %>%
  mutate(time_point =  as.numeric(str_extract(time_point, "\\d+")),
         day = 0,
         video_replicate = file) %>%
  select(time_point,
         day,
         video_replicate,
         file,
         bioarea_per_volume,
         indiv_per_volume)

species_ID_13_threshold_t0 = read.csv(here("2_data", 
                                           "species_ID_13_threshold", 
                                           paste0("t0.csv"))) %>%
  rename(Ble_indiv_per_volume = Ble,
         Cep_indiv_per_volume = Cep,
         Col_indiv_per_volume = Col,
         Eug_indiv_per_volume = Eug,
         Eup_indiv_per_volume = Eup,
         Lox_indiv_per_volume = Lox,
         Pau_indiv_per_volume = Pau,
         Pca_indiv_per_volume = Pca,
         Spi_indiv_per_volume = Spi,
         Spi_te_indiv_per_volume = Spi_te,
         Tet_indiv_per_volume = Tet) %>%
  select(file,
         all_of(species_IDD_with_13_threshold_indiv_per_volume))

species_ID_40_threshold_t0 = read.csv(here("2_data", 
                                           "species_ID_40_threshold", 
                                           paste0("t0.csv"))) %>%
  rename(Ble_indiv_per_volume = Ble,
         Cep_indiv_per_volume = Cep,
         Col_indiv_per_volume = Col,
         Eug_indiv_per_volume = Eug,
         Eup_indiv_per_volume = Eup,
         Lox_indiv_per_volume = Lox,
         Pau_indiv_per_volume = Pau,
         Pca_indiv_per_volume = Pca,
         Spi_indiv_per_volume = Spi,
         Spi_te_indiv_per_volume = Spi_te,
         Tet_indiv_per_volume = Tet) %>%
  select(file,
         all_of(species_IDD_with_40_threshold_indiv_per_volume))

ds_ecosystems_t0 = ds_ecosystems_t0 %>%
  left_join(species_ID_13_threshold_t0,
            by = "file") %>%
  left_join(species_ID_40_threshold_t0,
            by = "file") %>%
  mutate(file =  as.numeric(str_extract(file, "\\d+")))
# Elongate t0 dataset.

ds_ecosystems_t0_elongated <- list()

for (video_i in 1 : n_videos_taken_t0) {
  
  single_video = ds_ecosystems_t0 %>%
    filter(file == video_i)
  
  ds_ecosystems_t0_elongated[[video_i]] = ecosystems_info %>%
    mutate(time_point = 0,
           day = 0,
           file = single_video$file,
           video_replicate = single_video$video_replicate,
           bioarea_per_volume = single_video$bioarea_per_volume,
           indiv_per_volume = single_video$indiv_per_volume,
           Ble_indiv_per_volume = single_video$Ble_indiv_per_volume,
           Cep_indiv_per_volume = single_video$Cep_indiv_per_volume,
           Col_indiv_per_volume = single_video$Col_indiv_per_volume,
           Eug_indiv_per_volume = single_video$Eug_indiv_per_volume,
           Eup_indiv_per_volume = single_video$Eup_indiv_per_volume,
           Lox_indiv_per_volume = single_video$Lox_indiv_per_volume,
           Pau_indiv_per_volume = single_video$Pau_indiv_per_volume,
           Pca_indiv_per_volume = single_video$Pca_indiv_per_volume,
           Spi_indiv_per_volume = single_video$Spi_indiv_per_volume,
           Spi_te_indiv_per_volume = single_video$Spi_te_indiv_per_volume,
           Tet_indiv_per_volume = single_video$Tet_indiv_per_volume)
}

ds_ecosystems_t0_elongated = ds_ecosystems_t0_elongated %>%
  bind_rows()
# Clean the columns of t0

ds_ecosystems_t0 = ds_ecosystems_t0_elongated %>%
  select(file,
         time_point,
         day,
         culture_ID,
         video_replicate,
         bioarea_per_volume,
         indiv_per_volume,
         all_of(protist_species_indiv_per_volume))

expect_equal(nrow(ds_ecosystems_t0), 
             sum(n_videos_taken_t0 * n_cultures))
# Import and bind t1-t4

ds_ecosystems_t1_to_t4 = NULL

for (time_point_i in time_points_without_t0) {
  
  species_ID_13_threshold = read.csv(here("2_data", 
                                          "species_ID_13_threshold", 
                                          paste0("t", time_point_i, ".csv"))) %>%
    rename(Ble_indiv_per_volume = Ble,
           Cep_indiv_per_volume = Cep,
           Col_indiv_per_volume = Col,
           Eug_indiv_per_volume = Eug,
           Eup_indiv_per_volume = Eup,
           Lox_indiv_per_volume = Lox,
           Pau_indiv_per_volume = Pau,
           Pca_indiv_per_volume = Pca,
           Spi_indiv_per_volume = Spi,
           Spi_te_indiv_per_volume = Spi_te,
           Tet_indiv_per_volume = Tet) %>% 
    select(file,
           all_of(species_IDD_with_13_threshold_indiv_per_volume))
  
  
  species_ID_40_threshold = read.csv(here("2_data", 
                                          "species_ID_40_threshold", 
                                          paste0("t", time_point_i, ".csv"))) %>%
    rename(Ble_indiv_per_volume = Ble,
           Cep_indiv_per_volume = Cep,
           Col_indiv_per_volume = Col,
           Eug_indiv_per_volume = Eug,
           Eup_indiv_per_volume = Eup,
           Lox_indiv_per_volume = Lox,
           Pau_indiv_per_volume = Pau,
           Pca_indiv_per_volume = Pca,
           Spi_indiv_per_volume = Spi,
           Spi_te_indiv_per_volume = Spi_te,
           Tet_indiv_per_volume = Tet) %>% 
    select(file,
           all_of(species_IDD_with_40_threshold_indiv_per_volume))
  
  
  ds_ecosystems_t1_to_t4[[time_point_i]] = read.csv(here("2_data", 
                                                      "ecosystems_13_threshold", 
                                                      paste0("t", time_point_i, ".csv"))) %>%
    arrange(file) %>%
    mutate(video_replicate = rep(1 : time_point_day$video_replicates[time_point_i+1],
                                 each = n_cultures),
           day = time_point_day$day[time_point_day$time_point == time_point_i]) %>%
    select(file,
           time_point,
           day,
           video_replicate,
           file,
           culture_ID,
           bioarea_per_volume,
           indiv_per_volume)
  
  ds_ecosystems_t1_to_t4[[time_point_i]] = ds_ecosystems_t1_to_t4[[time_point_i]] %>%
    left_join(species_ID_13_threshold,
                by = "file") %>%
    left_join(species_ID_40_threshold,
                by = "file")
    
}

ds_ecosystems_t1_to_t4 = ds_ecosystems_t1_to_t4 %>%
  bind_rows()
# Bind t0 with t1-t4

ds_ecosystems = rbind(ds_ecosystems_t0,
                      ds_ecosystems_t1_to_t4) %>%
  left_join(ecosystems_info,
            by = "culture_ID") 
    
expect_equal(nrow(ds_ecosystems),
             sum(sum(time_point_day$video_replicates) * n_cultures))
# Reorder and rename columns

ds_ecosystems = ds_ecosystems %>%
  rename(ecosystem_size = patch_size,
         ecosystem_size_ml = patch_size_volume) %>%
  select(file,
         time_point,
         day,
         disturbance,
         culture_ID,
         system_nr,
         eco_metaeco_type,
         ecosystem_size,
         ecosystem_size_ml,
         metaecosystem,
         metaecosystem_type,
         video_replicate,
         bioarea_per_volume,
         indiv_per_volume,
         all_of(protist_species_indiv_per_volume)) %>% 
  rename(bioarea_µm2_per_μL = bioarea_per_volume) %>%
  rename_all( ~ gsub("volume", "μL", .))
# Rename and reorder levels

ds_ecosystems <- ds_ecosystems %>%
  mutate(ecosystem_size = case_when(ecosystem_size == "S" ~ "Small",
                                    ecosystem_size == "M" ~ "Medium",
                                    ecosystem_size == "L" ~ "Large",
                                    TRUE ~ ecosystem_size), 
         connection = case_when(eco_metaeco_type == "S" ~ "unconnected",
                                     eco_metaeco_type == "M" ~ "unconnected",
                                     eco_metaeco_type == "L" ~ "unconnected",
                                     eco_metaeco_type == "S (S_S)" ~ "connected to small",
                                     eco_metaeco_type == "S (S_L)" ~ "connected to large",
                                     eco_metaeco_type == "M (M_M)" ~ "connected to medium",
                                     eco_metaeco_type == "L (S_L)" ~ "connected to small",
                                     eco_metaeco_type == "L (L_L)" ~ "connected to large"), 
         ecosystem_type = paste(ecosystem_size, connection),
         metaecosystem_type = case_when(metaecosystem_type == "S_S" ~ "Small-Small",
                                        metaecosystem_type == "M_M" ~ "Medium-Medium",
                                        metaecosystem_type == "L_L" ~ "Large-Large",
                                        metaecosystem_type == "S_L" ~ "Small-Large",
                                        TRUE ~ metaecosystem_type),
    time_point =  as.numeric(str_extract(time_point, "\\d+")),
    file =  as.numeric(str_extract(file, "\\d+")))
# Change units of measurments to ml

ds_ecosystems = ds_ecosystems %>%
  mutate(bioarea_µm2_per_ml = bioarea_µm2_per_μL * 10^3,
         bioarea_mm2_per_ml = bioarea_µm2_per_ml * 10^(-6),
         Ble_indiv_per_ml = Ble_indiv_per_μL * 10^3,
         Cep_indiv_per_ml = Cep_indiv_per_μL * 10^3,
         Col_indiv_per_ml = Col_indiv_per_μL * 10^3,
         Eug_indiv_per_ml = Eug_indiv_per_μL * 10^3,
         Eup_indiv_per_ml = Eup_indiv_per_μL * 10^3,
         Lox_indiv_per_ml = Lox_indiv_per_μL * 10^3,
         Pau_indiv_per_ml = Pau_indiv_per_μL * 10^3,
         Pca_indiv_per_ml = Pca_indiv_per_μL * 10^3,
         Spi_indiv_per_ml = Spi_indiv_per_μL * 10^3,
         Spi_te_indiv_per_ml = Spi_te_indiv_per_μL * 10^3,
         Tet_indiv_per_ml = Tet_indiv_per_μL * 10^3)
# Take off problematic videos

ds_ecosystems_before_taking_off_videos = ds_ecosystems

ds_ecosystems = ds_ecosystems %>%
  filter(!(time_point %in% videos_to_take_off$time_point & file %in% videos_to_take_off$file))

diff = setdiff(ds_ecosystems_before_taking_off_videos, ds_ecosystems)

expect_equal(nrow(videos_to_take_off),
             nrow(expand.grid(diff$culture_ID, diff$time_point, diff$file) %>% unique()))
# Take off problematic cultures 

ds_ecosystems_before_taking_off_cultures = ds_ecosystems

ds_ecosystems = ds_ecosystems %>%
  filter(!culture_ID %in% ecosystems_to_take_off)

expect_equal(setdiff(ds_ecosystems_before_taking_off_cultures, 
                     ds_ecosystems) %>% 
               pull(culture_ID) %>% 
               unique(),
             ecosystems_to_take_off)
# Average videos

ds_ecosystems = ds_ecosystems %>%
  group_by(across(all_of(columns_ecosystems))) %>%
  summarise(across(contains("_per_ml"), mean),
            across(contains("_tot"), mean)) %>%
  ungroup()

expect_equal(nrow(ds_ecosystems), 
             (n_cultures - length(ecosystems_to_take_off)) * length(time_points))
# Add connection and individuals

ds_ecosystems = ds_ecosystems %>%
  mutate(indiv_per_ml = !!rlang::parse_expr(paste(protist_species_indiv_per_ml, 
                                                  collapse = " + ")))
# Calculate total response variable for the whole ecosystem

ds_ecosystems = ds_ecosystems %>%
  mutate(bioarea_tot_mm2 = bioarea_mm2_per_ml * ecosystem_size_ml,
         indiv_tot = indiv_per_ml * ecosystem_size_ml,
         Ble_tot_indiv = Ble_indiv_per_ml * ecosystem_size_ml,
         Cep_tot_indiv = Cep_indiv_per_ml * ecosystem_size_ml,
         Col_tot_indiv = Col_indiv_per_ml * ecosystem_size_ml,
         Eug_tot_indiv = Eug_indiv_per_ml * ecosystem_size_ml,
         Eup_tot_indiv = Eup_indiv_per_ml * ecosystem_size_ml,
         Lox_tot_indiv = Lox_indiv_per_ml * ecosystem_size_ml,
         Pau_tot_indiv = Pau_indiv_per_ml * ecosystem_size_ml,
         Pca_tot_indiv = Pca_indiv_per_ml * ecosystem_size_ml,
         Spi_tot_indiv = Spi_indiv_per_ml * ecosystem_size_ml,
         Spi_te_tot_indiv = Spi_te_indiv_per_ml * ecosystem_size_ml,
         Tet_tot_indiv = Tet_indiv_per_ml * ecosystem_size_ml)
# Calculate species dominance

ds_ecosystems = ds_ecosystems %>%
  mutate(across(.cols = all_of(protist_species_indiv_per_ml), 
                .fns = list(dominance = ~ (. / indiv_per_ml) * 100), 
                .names = "{col}_dominance"))

expect_equal(unique(ds_ecosystems$Ble_indiv_per_ml_dominance[ds_ecosystems$indiv_per_ml == 0]), NaN)

if (FALSE %in% unique((ds_ecosystems$Ble_indiv_per_ml/ds_ecosystems$indiv_per_ml) *100 == ds_ecosystems$Ble_indiv_per_ml_dominance)) stop()
# Calculate alpha diversity (Shannon, Simpson, Inverse Simpson, Evenness)

n_rows_ds_ecosystems_before_calculating_alpha = nrow(ds_ecosystems)

ds_ecosystems = calculate.alpha.diversity()

expect_equal(max(ds_ecosystems$species_richness), 
             length(protist_species))

expect_equal(nrow(ds_ecosystems),
             n_rows_ds_ecosystems_before_calculating_alpha)
# Calculate median body size

n_rows_ds_ecosystems_before_median_size = nrow(ds_ecosystems)

ds_median_body_size = ds_individuals %>%
  group_by(time_point,
           culture_ID,
           file) %>%
  summarise(median_body_area_µm2 = median(body_area_µm2)) %>%
  group_by(time_point,
           culture_ID) %>%
  summarise(median_body_area_µm2 = mean(median_body_area_µm2))

expect_true(nrow(ds_median_body_size) <= nrow(ds_ecosystems)) #Ds median body size could be less because some cultures might be crashed and not have any individual.

ds_ecosystems_before_full_join = ds_ecosystems

ds_ecosystems = full_join(ds_ecosystems, ds_median_body_size)

expect_equal(nrow(ds_ecosystems), 
             n_rows_ds_ecosystems_before_median_size)
# Calculate auto/heterotrophic ratio

ds_ecosystems = ds_ecosystems %>%
  mutate(auto_hetero_ratio = (Eug_indiv_per_ml + Eup_indiv_per_ml) / 
                             (Ble_indiv_per_ml + 
                              Cep_indiv_per_ml + 
                              Col_indiv_per_ml + 
                              Lox_indiv_per_ml + 
                              Pau_indiv_per_ml + 
                              Pca_indiv_per_ml +
                              Spi_indiv_per_ml + 
                              Spi_te_indiv_per_ml +
                              Tet_indiv_per_ml))
# Add evaporation rates

ds_for_evaporation = read.csv(here("2_data", "water_addition.csv")) %>%
  pivot_longer(cols = starts_with("water_add_after_t"), 
               names_to = "time_point",          
               values_to = "water_addition_ml") %>%
  mutate(time_point = as.double(str_extract(time_point, "\\d+")) + 1)

ds_ecosystems = ds_ecosystems %>%
  left_join(ds_for_evaporation)

Patch effect sizes (ds_ecosystems_effect_size)

In this dataset (ds_ecosystems_effect_size) each row represents a treatment at a time point. It contains the effect size of the connection of a ecosystem (connected vs unconnected).

# Calculate the mean & sd of response variables for each treatment/control at each time point

ds_ecosystems_effect_size = NULL
variable_nr = 0

for (variable_i in variables_ecosystems) {
  
  variable_nr = variable_nr + 1
  
  ds_ecosystems_effect_size[[variable_nr]] = ds_ecosystems %>%
    filter(time_point >= 1,
           !is.na(!!sym(variable_i))) %>%
    group_by(across(all_of(columns_ecosystems[columns_ecosystems != "culture_ID" & 
                                           columns_ecosystems != "system_nr"]))) %>%
    summarise(across(all_of(variable_i),
                     list(mean = mean,
                          sd = sd)),
              sample_size = n()) %>%
    rename_with( ~ paste0(variable_i, "_sample_size"),
                 matches("sample_size"))
  
}

ds_ecosystems_effect_size <- reduce(ds_ecosystems_effect_size,
                                    full_join,
                                    by = columns_ecosystems[columns_ecosystems != "culture_ID" & columns_ecosystems != "system_nr"])

expect_equal(nrow(ds_ecosystems_effect_size),
             n_ecosystem_types * (n_time_points-1) * n_disturbance_levels)
# Calculate the effect size (Hedge's d) for each treatment at each time point
  
  for (variable_i in variables_ecosystems) {
    ds_ecosystems_effect_size <- ds_ecosystems_effect_size %>%
      mutate(!!paste0(variable_i, "_d") := NA,
             !!paste0(variable_i, "_d_upper") := NA,
             !!paste0(variable_i, "_d_lower") := NA)
  }
  
  row_i = 0
  for (treatment_selected in treatments_and_controls$treatment) {
    for (time_point_selected in time_points) {
      
      row_i = row_i + 1
      
      control_input = treatments_and_controls$control[treatments_and_controls$treatment == treatment_selected]
      
      treatment_row = ds_ecosystems_effect_size %>%
        filter(ecosystem_type == treatment_selected,
               time_point == time_point_selected)
      
      control_row = ds_ecosystems_effect_size %>%
        filter(ecosystem_type == control_input,
               time_point == time_point_selected)
      
      for (response_variable in variables_ecosystems) {
        
        hedges_d = calculate.hedges_d(treatment_row[[paste0(response_variable, "_mean")]],
                                      treatment_row[[paste0(response_variable, "_sd")]],
                                      treatment_row[[paste0(response_variable, "_sample_size")]],
                                      control_row[[paste0(response_variable, "_mean")]],
                                      control_row[[paste0(response_variable, "_sd")]],
                                      control_row[[paste0(response_variable, "_sample_size")]])
        
        ds_ecosystems_effect_size[[paste0(response_variable, "_d")]][
          ds_ecosystems_effect_size$ecosystem_type == treatment_selected &
          ds_ecosystems_effect_size$time_point == time_point_selected] =
          hedges_d$d
        
        ds_ecosystems_effect_size[[paste0(response_variable, "_d_upper")]][
          ds_ecosystems_effect_size$ecosystem_type == treatment_selected &
          ds_ecosystems_effect_size$time_point == time_point_selected] =
          hedges_d$upper_CI
        
        ds_ecosystems_effect_size[[paste0(response_variable, "_d_lower")]][
          ds_ecosystems_effect_size$ecosystem_type == treatment_selected &
          ds_ecosystems_effect_size$time_point == time_point_selected] =
          hedges_d$lower_CI
        
      }
    }
  }

expect_equal(nrow(ds_ecosystems_effect_size),
             n_ecosystem_types * (n_time_points-1) * n_disturbance_levels)

Meta-ecosystems (ds_metaecosystems)

In this dataset (ds_metaecosystems) each row represents a meta-ecosystem or a two-ecosystem unconnected system at a time point.

# --- Find the IDs of unconnected ecosystems --- #

ID_unconnected_S_low = ds_ecosystems %>%
  filter(ecosystem_type == "Small unconnected",
         disturbance == "low") %>%
  pull(culture_ID) %>%
  unique()

ID_unconnected_M_low = ds_ecosystems %>%
  filter(ecosystem_type == "Medium unconnected",
         disturbance == "low") %>%
  pull(culture_ID) %>%
  unique()

ID_unconnected_L_low = ds_ecosystems %>%
  filter(ecosystem_type == "Large unconnected",
         disturbance == "low") %>%
  pull(culture_ID) %>%
  unique()

ID_unconnected_S_high = ds_ecosystems %>%
  filter(ecosystem_type == "Small unconnected",
         disturbance == "high") %>%
  pull(culture_ID) %>%
  unique()

ID_unconnected_M_high = ds_ecosystems %>%
  filter(ecosystem_type == "Medium unconnected",
         disturbance == "high") %>%
  pull(culture_ID) %>%
  unique()

ID_unconnected_L_high = ds_ecosystems %>%
  filter(ecosystem_type == "Large unconnected",
         disturbance == "high") %>%
  pull(culture_ID) %>%
  unique()
# --- Find combinations of ecosystems to create unconnected meta-ecosystems --- #

combinations_S_and_L_low = crossing(ID_unconnected_S_low,
                                    ID_unconnected_L_low) %>%
                            mutate(disturbance = "low",
                                   metaecosystem_type = "Small-Large",
                                   connection = "unconnected") %>%
                            rename(ID_first_ecosystem = ID_unconnected_S_low,
                                   ID_second_ecosystem = ID_unconnected_L_low) %>%
                            select(disturbance,
                                   metaecosystem_type,
                                   connection,
                                   ID_first_ecosystem,
                                   ID_second_ecosystem)

combinations_S_and_L_high = crossing(ID_unconnected_S_high,
                                     ID_unconnected_L_high) %>%
                            mutate(disturbance = "high",
                                   metaecosystem_type = "Small-Large",
                                   connection = "unconnected") %>%
                            rename(ID_first_ecosystem = ID_unconnected_S_high,
                                   ID_second_ecosystem = ID_unconnected_L_high) %>%
                            select(disturbance,
                                   metaecosystem_type,
                                   connection,
                                   ID_first_ecosystem,
                                   ID_second_ecosystem)

combinations_M_and_M_low = combinat::combn(ID_unconnected_M_low,
                                           m = 2) %>%
                            t() %>%
                            as.data.frame() %>%
                            rename(ID_first_ecosystem = V1,
                                   ID_second_ecosystem = V2) %>%
                            mutate(disturbance = "low",
                                   metaecosystem_type = "Medium-Medium",
                                   connection = "unconnected") %>%
                            select(disturbance,
                                   metaecosystem_type,
                                   connection,
                                   ID_first_ecosystem,
                                   ID_second_ecosystem)

combinations_M_and_M_high = combinat::combn(ID_unconnected_M_high,
                                            m = 2) %>%
                            t() %>%
                            as.data.frame() %>%
                            rename(ID_first_ecosystem = V1,
                                   ID_second_ecosystem = V2) %>%
                            mutate(disturbance = "high",
                                   metaecosystem_type = "Medium-Medium",
                                   connection = "unconnected") %>%
                            select(disturbance,
                                   metaecosystem_type,
                                   connection,
                                   ID_first_ecosystem,
                                   ID_second_ecosystem)
# --- Bind ecosystem combinations --- #

combinations_unconnected_metaeco = rbind(combinations_S_and_L_low,
                                         combinations_S_and_L_high,
                                         combinations_M_and_M_low,
                                         combinations_M_and_M_high) %>% 
  mutate(system_nr = 1001:(1000 + nrow(.))) %>%
  select(system_nr,
         disturbance,
         metaecosystem_type,
         connection,
         ID_first_ecosystem,
         ID_second_ecosystem)
# --- Find combinations of ecosystems to create connected meta-ecosystems --- #

combinations_connected_metaeco = ds_ecosystems %>%
  filter(time_point == 0,
         metaecosystem == "yes") %>%
  select(system_nr,
         disturbance,
         metaecosystem_type,
         culture_ID) %>%
  group_by(system_nr,
           disturbance,
           metaecosystem_type) %>%
  summarise(ID_first_ecosystem = (mean(culture_ID) - 0.5),
            ID_second_ecosystem = (mean(culture_ID) + 0.5)) %>%
  mutate(connection = "connected") %>%
  as.data.frame()
# --- Bind combinations of ecosystems to create unconnected and connected meta-ecosystems --- #

ecosystem_combinations = rbind(combinations_unconnected_metaeco,
                               combinations_connected_metaeco) %>%
  mutate(ecosystems_combined = paste0(ID_first_ecosystem, "|", ID_second_ecosystem))

n_ecosystems_combinations = nrow(ecosystem_combinations)
# --- Create sets for SL unconnected, where in each set a small and a large ecosystems are paired differently --- #

#I keep the small ecosystems on the same order and perform permutations on large ecosystems

SL_unconnected_sys_sets <- vector("list",
                                  length(disturbance_levels))

for (disturbance_i in 1:length(disturbance_levels)) {
  
  ID_small_ecosystems = ds_ecosystems %>%
    filter(disturbance == disturbance_levels[disturbance_i],
           ecosystem_type == "Small unconnected") %>%
    pull(culture_ID) %>%
    unique()
  
  ID_large_ecosystems = ds_ecosystems %>%
    filter(disturbance == disturbance_levels[disturbance_i],
           ecosystem_type == "Large unconnected") %>%
    pull(culture_ID) %>%
    unique()
  
  #Force small and large ecosystems vectors to have the same length
  
  length_difference <- length(ID_small_ecosystems) - length(ID_large_ecosystems)
  if (length_difference > 0) {
    
    ID_large_ecosystems = c(ID_large_ecosystems,
                       rep("Patch taken off",
                           times = abs(length(ID_small_ecosystems) - 
                                       length(ID_large_ecosystems))))
    
    } else if (length_difference < 0) {
      
    ID_small_ecosystems = c(ID_small_ecosystems,
                         rep("Patch taken off",
                             times = abs(length(ID_large_ecosystems) - 
                                         length(ID_small_ecosystems))))
    }

  # Create dataframe
  
  permutations_large = permn(ID_large_ecosystems)
  
  SL_unconnected_sys_sets[[disturbance_i]] = data.frame(disturbance = disturbance_levels[disturbance_i],
                                                        metaecosystem_type = "Small-Large",
                                                        connection = "unconnected",
                                                        ID_first_ecosystem = rep(ID_small_ecosystems, times = length(permutations_large)),
                                                        ID_second_ecosystem = unlist(permutations_large),
                                                        set = rep(1 : length(permutations_large), 
                                                                  each = length(ID_small_ecosystems)))
  
  expect_equal(nrow(SL_unconnected_sys_sets[[disturbance_i]]),
               length(ID_small_ecosystems) * length(permutations_large))
  
  SL_unconnected_sys_sets[[disturbance_i]] = SL_unconnected_sys_sets[[disturbance_i]] %>%
    filter(!ID_first_ecosystem == "Patch taken off",
           !ID_second_ecosystem == "Patch taken off") %>%
    mutate(ID_first_ecosystem = as.double(ID_first_ecosystem),
           ID_second_ecosystem = as.double(ID_second_ecosystem)) %>%
    full_join(ecosystem_combinations %>%
                filter(disturbance == disturbance_levels[disturbance_i], 
                       metaecosystem_type == "Small-Large",
                       connection == "unconnected")) #Add system_nr & ecosystems_combined

}

SL_unconnected_sys_sets_before_binding = SL_unconnected_sys_sets
SL_unconnected_sys_sets = SL_unconnected_sys_sets %>%
  bind_rows()
expect_equal(nrow(SL_unconnected_sys_sets),
             nrow(SL_unconnected_sys_sets_before_binding[[1]]) + nrow(SL_unconnected_sys_sets_before_binding[[2]]))

expect_equal(length(SL_unconnected_sys_sets %>% 
                      pull(system_nr) %>% 
                      unique()),
             length(ecosystem_combinations %>%
                      filter(metaecosystem_type == "Small-Large",
                             connection == "unconnected") %>%
                      pull(system_nr) %>%
                      unique()))
# --- Create sets for MM unconnected, where in each set two different medium ecosystems are paired--- #

#To do so, I ... 

#Initialise MM_unconnected_sets. Assign 10^4 rows to each matrix so that we have enough rows not to run out of them when we try to assign values to them. Assign 4 columns which will include culture_ID of the first system, second culture_ID of the fist system, culture_ID of the second system, and second culture_ID of the second system.  

MM_unconnected_sets = NULL
for(disturbance_i in 1:length(disturbance_levels)){
  
  MM_unconnected_sets[[disturbance_i]] <- matrix(nrow = 10 ^ 4, 
                                                 ncol = 4)
  
}

for (disturbance_i in 1:length(disturbance_levels)) {
  
  ID_medium_ecosystems = ds_ecosystems %>%
    filter(disturbance == disturbance_levels[disturbance_i],
           ecosystem_type == "Medium unconnected") %>%
    pull(culture_ID) %>%
    unique()
  
  MM_unconnected_systems = combn(ID_medium_ecosystems, 
                              2) %>%
    t()
  
  matrix_row = 0
  for (first_system_i in 1:nrow(MM_unconnected_systems)) {
    
    #Find culture IDs of the first system (what's the first system?)
    first_system = MM_unconnected_systems[first_system_i, ]
    
    for (second_system_i in 1:nrow(MM_unconnected_systems)) {
      
      #Find culture IDs of the second system (what's the second system?)
      second_system = MM_unconnected_systems[second_system_i, ]
      
      shared_elements_among_systems = intersect(first_system,
                                                second_system)
      
      if (length(shared_elements_among_systems) == 0) {
        
        matrix_row = matrix_row + 1
        
        #Make first and second system into a set
        MM_unconnected_sets[[disturbance_i]][matrix_row,] = c(first_system,
                                                            second_system)
        
        print(MM_unconnected_sets[[disturbance_i]][matrix_row,])
        
      }
    }
  }
  
  #Tidy the dataset with all the ecosystem combinations
  MM_unconnected_sets[[disturbance_i]] = MM_unconnected_sets[[disturbance_i]] %>%
    as.data.frame() %>%
    drop_na()
  
  expect_equal(MM_unconnected_sets[[disturbance_i]] %>% 
                 filter(V1 == V2 | V1 == V3 | V1 == V4 | V2 == V3 | V2 == V4 | V3 == V4) %>% 
                 nrow(),
               0)
  
  #Reorder the dataset with all the ecosystem combinations
  MM_unconnected_sets_reordered = data.frame(ID_first_ecosystem = NA,
                                          ID_second_ecosystem = NA,
                                          set = NA)
  
  for (set_input in 1:nrow(MM_unconnected_sets[[disturbance_i]])) {
    MM_unconnected_sets_reordered = MM_unconnected_sets_reordered %>%
      add_row(ID_first_ecosystem = MM_unconnected_sets[[disturbance_i]][set_input, 1],
              ID_second_ecosystem = MM_unconnected_sets[[disturbance_i]][set_input, 2],
              set = set_input) %>%
      add_row(ID_first_ecosystem = MM_unconnected_sets[[disturbance_i]][set_input, 3],
              ID_second_ecosystem = MM_unconnected_sets[[disturbance_i]][set_input, 4],
              set = set_input)
  }
  
  #Add to a list
  MM_unconnected_sets[[disturbance_i]] = MM_unconnected_sets_reordered %>%
    drop_na() %>%
    mutate(disturbance = disturbance_levels[disturbance_i],
           metaecosystem_type = "Medium-Medium",
           connection = "unconnected")
  
  #Add system nr
  ID_combinations_MM_unconnected = ecosystem_combinations %>%
    filter(disturbance == disturbance_levels[disturbance_i],
           metaecosystem_type == "Medium-Medium",
           connection == "unconnected")
  
  MM_unconnected_sets[[disturbance_i]] = full_join(MM_unconnected_sets[[disturbance_i]],
                                                   ID_combinations_MM_unconnected)
  
}
## [1] 6 7 8 9
## [1]  6  7  8 10
## [1]  6  7  9 10
## [1] 6 8 7 9
## [1]  6  8  7 10
## [1]  6  8  9 10
## [1] 6 9 7 8
## [1]  6  9  7 10
## [1]  6  9  8 10
## [1]  6 10  7  8
## [1]  6 10  7  9
## [1]  6 10  8  9
## [1] 7 8 6 9
## [1]  7  8  6 10
## [1]  7  8  9 10
## [1] 7 9 6 8
## [1]  7  9  6 10
## [1]  7  9  8 10
## [1]  7 10  6  8
## [1]  7 10  6  9
## [1]  7 10  8  9
## [1] 8 9 6 7
## [1]  8  9  6 10
## [1]  8  9  7 10
## [1]  8 10  6  7
## [1]  8 10  6  9
## [1]  8 10  7  9
## [1]  9 10  6  7
## [1]  9 10  6  8
## [1]  9 10  7  8
## [1] 61 62 63 64
## [1] 61 62 63 65
## [1] 61 62 64 65
## [1] 61 63 62 64
## [1] 61 63 62 65
## [1] 61 63 64 65
## [1] 61 64 62 63
## [1] 61 64 62 65
## [1] 61 64 63 65
## [1] 61 65 62 63
## [1] 61 65 62 64
## [1] 61 65 63 64
## [1] 62 63 61 64
## [1] 62 63 61 65
## [1] 62 63 64 65
## [1] 62 64 61 63
## [1] 62 64 61 65
## [1] 62 64 63 65
## [1] 62 65 61 63
## [1] 62 65 61 64
## [1] 62 65 63 64
## [1] 63 64 61 62
## [1] 63 64 61 65
## [1] 63 64 62 65
## [1] 63 65 61 62
## [1] 63 65 61 64
## [1] 63 65 62 64
## [1] 64 65 61 62
## [1] 64 65 61 63
## [1] 64 65 62 63
#Bind all sets of MM unconnected
MM_unconnected_sets = MM_unconnected_sets %>%
  bind_rows()
expect_equal(length(MM_unconnected_sets %>%
                      pull(system_nr) %>%
                      unique()),
             length(ecosystem_combinations %>%
                      filter(metaecosystem_type == "Medium-Medium",
                             connection == "unconnected") %>%
                      pull(system_nr) %>%
                      unique()))
# --- Bind SL and MM unconnected systems --- #

unconnected_combinations_sets = rbind(SL_unconnected_sys_sets, 
                                   MM_unconnected_sets) %>%
  select(disturbance,
         metaecosystem_type,
         connection,
         set,
         system_nr,
         ID_first_ecosystem,
         ID_second_ecosystem)
  • Each row is a meta-ecosystem.

  • It contains also “fake” meta-ecosystems which I created from unconnected ecosystems (metaecosystem type = Small-Large unconnected & metaecosystem type = Medium-Medium unconnected).

  • Warning appear after the following code, as:

  1. alpha diversity is computed for a culture that is totally crashed, so it has not meaning.
  2. beta diversity is computed between a culture that is still alive and one that is totally crashed. Because one of the cultures is totally crashed, the Bray-Curtis index is 1.
# --- Compute meta-ecosystems for each time point --- #

ds_metaecosystems = NULL
row_i = 0
for (combination_i in 1:n_ecosystems_combinations) {
  for (time_point_selected in time_points) {
    
    row_i = row_i + 1
    
    current_day = sampling_days[time_point_selected + 1]
    current_system_nr = ecosystem_combinations[combination_i, ]$system_nr
    current_combination = ecosystem_combinations[combination_i, ]$ecosystems_combined
    current_disturbance = ecosystem_combinations[combination_i, ]$disturbance
    current_metaeco_type = ecosystem_combinations[combination_i, ]$metaecosystem_type
    current_connection = ecosystem_combinations[combination_i, ]$connection
    current_IDs = c(ecosystem_combinations[combination_i, ]$ID_first_ecosystem,
                    ecosystem_combinations[combination_i, ]$ID_second_ecosystem)
    
    if (current_system_nr %in% metaecosystems_to_take_off)
      next
    
    if (current_IDs[1] == current_IDs[2])
      next
    
    species_vector_two_ecosystems = ds_ecosystems %>%
      filter(time_point == time_point_selected,
             culture_ID %in% current_IDs) %>%
      ungroup() %>%
      select(all_of(protist_species_indiv_per_ml))
    
    absence_presence_two_ecosystems <-
      ifelse(species_vector_two_ecosystems > 0, 1, 0)
    
    #Alpha diversity: Shannon (mean between the two ecosystems)
    shannon_ecosystem_1 = diversity(species_vector_two_ecosystems[1, ], index = "shannon")
    shannon_ecosystem_2 = diversity(species_vector_two_ecosystems[2, ], index = "shannon")
    shannon_value = (shannon_ecosystem_1 + shannon_ecosystem_2) / 2
    
    #Alpha diversity: Species richness (mean between the two ecosystems)
    richness_ecosystem_1 = specnumber(species_vector_two_ecosystems[1, ])
    richness_ecosystem_2 = specnumber(species_vector_two_ecosystems[2, ])
    mean_richness_value = (richness_ecosystem_1 + richness_ecosystem_2) / 2
    
    #Beta diversity: Jaccard
    jaccard_index_value = vegdist(species_vector_two_ecosystems,
                                  method = "jaccard") %>%
      as.numeric()
    
    #Beta diversity: Bray Curtis
    bray_curtis_value = vegdist(species_vector_two_ecosystems,
                                method = "bray") %>%
      as.numeric()
    
    #Beta diversity: partitioning of beta diversity from Sorensen index into turnover (Simpson pair-wise dissimilarity) and nestedness (nestedness-fraction of Sorensen)
    betapart_core_object = betapart.core(absence_presence_two_ecosystems)
    beta_spatial_turnover_value = beta.pair(betapart_core_object)$beta.sim %>% as.double()
    beta_nestedness_value = beta.pair(betapart_core_object)$beta.sne %>% as.double()
    beta_total_value = beta.pair(betapart_core_object)$beta.sor %>% as.double()
    
    #Gamma diversity: Meta-ecosystem richness
    metaecosystem_richness_value = colSums(species_vector_two_ecosystems) %>%
      specnumber()
    
    #Put everything together
    ds_metaecosystems[[row_i]] = ds_ecosystems %>%
      filter(culture_ID %in% current_IDs,
             time_point == time_point_selected) %>%
      summarise(total_metaecosystem_bioarea_mm2 = sum(bioarea_tot_mm2),
                total_metaecosystem_Ble_indiv = sum(Ble_tot_indiv),
                total_metaecosystem_Cep_indiv = sum(Cep_tot_indiv),
                total_metaecosystem_Col_indiv = sum(Col_tot_indiv),
                total_metaecosystem_Eug_indiv = sum(Eug_tot_indiv),
                total_metaecosystem_Eup_indiv = sum(Eup_tot_indiv),
                total_metaecosystem_Lox_indiv = sum(Lox_tot_indiv),
                total_metaecosystem_Pau_indiv = sum(Pau_tot_indiv),
                total_metaecosystem_Pca_indiv = sum(Pca_tot_indiv),
                total_metaecosystem_Spi_indiv = sum(Spi_tot_indiv),
                total_metaecosystem_Spi_te_indiv = sum(Spi_te_tot_indiv),
                total_metaecosystem_Tet_indiv = sum(Tet_tot_indiv),
                total_water_addition_ml = sum(water_addition_ml)) %>%
      mutate(system_nr = current_system_nr,
             ecosystems_combined = current_combination,
             metaecosystem_type = current_metaeco_type,
             ecosystem_size_symmetry = case_when(metaecosystem_type == "Small-Large" ~ "asymmetric",
                                                 metaecosystem_type == "Medium-Medium" ~ "symmetric",
                                                 metaecosystem_type == "Small-Small" ~ "symmetric",
                                                 metaecosystem_type == "Large-Large" ~ "symmetric"),
             connection = current_connection,
             disturbance = current_disturbance,
             time_point = time_point_selected,
             day = current_day,
             jaccard_index = jaccard_index_value,
             bray_curtis = bray_curtis_value,
             beta_spatial_turnover = beta_spatial_turnover_value,
             beta_nestedness = beta_nestedness_value,
             beta_total = beta_total_value,
             metaecosystem_richness = metaecosystem_richness_value,
             mean_shannon = shannon_value,
             mean_richness = mean_richness_value) %>%
      ungroup()
    
  }
}
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): missing
## values in results
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): missing
## values in results
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): missing
## values in results
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): missing
## values in results
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
## Warning in vegdist(species_vector_two_ecosystems, method = "jaccard"): you have empty rows: their dissimilarities may be
##                  meaningless in method "jaccard"
## Warning in vegdist(species_vector_two_ecosystems, method = "bray"): you have empty rows: their dissimilarities may be
##                  meaningless in method "bray"
ds_metaecosystems = ds_metaecosystems %>%
  bind_rows() %>%
  as.data.frame() %>%
  select(time_point,
         day,
         system_nr,
         ecosystems_combined,
         disturbance,
         metaecosystem_type,
         ecosystem_size_symmetry,
         connection,
         mean_shannon,
         mean_richness,
         jaccard_index,
         bray_curtis,
         beta_spatial_turnover,
         beta_nestedness,
         beta_total,
         metaecosystem_richness,
         total_metaecosystem_bioarea_mm2,
         paste0("total_metaecosystem_", protist_species, "_indiv"),
         total_water_addition_ml)
expect_equal(nrow(ds_metaecosystems), 
             n_time_points * n_ecosystems_combinations)

Filter according to disturbance

Here I’m filtering ecosystems to have only the ones with disturbance low.

ds_ecosystems_both_disturbances = ds_ecosystems
ds_metaecosystems_both_disturbances = ds_metaecosystems
#Filter data sets according to the global disturbance
ds_individuals = ds_individuals %>%
  filter(disturbance == disturbance_global_selected)
ds_ecosystems = ds_ecosystems %>%
  filter(disturbance == disturbance_global_selected)
ds_ecosystems_effect_size = ds_ecosystems_effect_size %>%
  filter(disturbance == disturbance_global_selected)
ds_metaecosystems = ds_metaecosystems %>%
  filter(disturbance == disturbance_global_selected)
ds_classes = ds_classes %>%
  filter(disturbance == disturbance_global_selected)
ds_classes_effect_size = ds_classes_effect_size %>%
  filter(disturbance == disturbance_global_selected)

Plots & Analysis

All meta-ecosystems

metaecosystem_type_selected = c("Small-Small",
                                "Large-Large",
                                "Medium-Medium",
                                "Small-Large")

connection_selected = c("connected",
                        "unconnected")

Alpha

response_variable_selected = "mean_shannon"

Here we want to look at how this meta-ecosystem variable changed across time by plotting its mean ± 95 confidence interval:

plot.metaecos.points(ds_metaecosystems,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Data represented through the single replicates
plot.metaecos.replicates(ds_metaecosystems,
                         metaecosystem_type_selected,
                         response_variable_selected)


Beta

response_variable_selected = "bray_curtis"

Here we want to look at how this meta-ecosystem variable changed across time by plotting its mean ± 95 confidence interval:

plot.metaecos.points(ds_metaecosystems,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Data represented through the single replicates
plot.metaecos.replicates(ds_metaecosystems,
                         metaecosystem_type_selected,
                         response_variable_selected)


Gamma

response_variable_selected = "metaecosystem_richness"

Here we want to look at how this meta-ecosystem variable changed across time by plotting its mean ± 95 confidence interval:

plot.metaecos.points(ds_metaecosystems,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Data represented through the single replicates
plot.metaecos.replicates(ds_metaecosystems,
                         metaecosystem_type_selected,
                         response_variable_selected)


Biomass

response_variable_selected = "total_metaecosystem_bioarea_mm2"

Here we want to look at how this meta-ecosystem variable changed across time by plotting its mean ± 95 confidence interval:

plot.metaecos.points(ds_metaecosystems,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Data represented through the single replicates
plot.metaecos.replicates(ds_metaecosystems,
                         metaecosystem_type_selected,
                         response_variable_selected)


SL vs MM

Alpha

response_variable_selected = "mean_shannon"
metaecosystem_type_selected = c("Medium-Medium",
                                "Small-Large")

Here we want to look at how this meta-ecosystem variable changed across time by plotting its mean ± 95 confidence interval:

plot.metaecos.points(ds_metaecosystems,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Data represented through the single replicates
plot.metaecos.replicates(ds_metaecosystems,
                         metaecosystem_type_selected,
                         response_variable_selected)



Following the initial inspection, we proceed to analyse differences among meta-ecosystems. To make it easier to interpret differences, we decided to construct a model for each comparisons we are interested in, which are: SL (connected vs unconnected) and MM (connected vs unconnected).

comparison_type = "all"
SL
metaecosystem_type_selected = c("Small-Large")

Our first step in the data analysis involves filtering the data to isolate the relevant data. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure we filtered data the right way.

# --- FILTER DATA --- #

filtered_data = ds_metaecosystems %>%
  filter(time_point %in% time_points_model,
         metaecosystem_type %in% metaecosystem_type_selected,
         !is.na(!!sym("total_water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.metaecos.points(filtered_data,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Then, given that we have gathered measurements from the same meta-ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this meta-ecosystem variable. To study the effects of connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat system nr as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). We also include the total water that was added due to evaporation in the microwave and the time point before the first disturbance (baseline). In the syntax of lmer4 the three models look this this:

Full model = response_variable ~connection * scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Reduced model = response_variable ~connection + scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Null model = response_variable ~scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Unconnected meta-ecosystems are made of paired unconnected ecosystems, which are paired randomly. However, how to pair unconnected ecosystems can be done in multiple ways, as unconnected ecosystems did not interact and therefore any combination between ecosystems would be arbitrary. To make sure that the random combination we selected did not bias our results, we run all the possible combinations of ecosystems constituting unconnected meta-ecosystems. The ecosystem combinations are into the objects unconnected_combinations_sets (Data > Meta-ecosystems). We therefore compute a p-value for each unconnected ecosystems combination, creating a p-value distribution. We keep as p-value of the comparison the median of such distributions.

Code we used to computed the p-values

 

# --- ADD BASELINES --- #

baselines = ds_metaecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(system_nr,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- PREPARE TO COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

unconnected_combinations_sets_filtered =  unconnected_combinations_sets %>%
  filter(disturbance == disturbance_global_selected,
         metaecosystem_type %in% metaecosystem_type_selected)

n_sets = unconnected_combinations_sets_filtered %>%
  pull(set) %>%
  max()

iterated_results_table = data.frame(Response = as.character(NA),
                                    Levels = as.character(NA),
                                    ΔAIC_full = NA,
                                    p_full = NA,
                                    ΔR2_full = NA,
                                    ΔAIC_fix = NA,
                                    p_fix = NA,
                                    ΔR2_fix = NA,
                                    combination_set = NA,
                                    system_nr_unconnected_systems = as.character(NA)) %>%
  slice(-1)
# --- COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

for (set_i in 1:n_sets) {
  
  # Filter the data to contain all the connected meta-ecosystems and only a subset of unconnected meta-ecosystems
  
  system_nr_unconnected_systems_selected = unconnected_combinations_sets_filtered %>%
    filter(metaecosystem_type %in% metaecosystem_type_selected,
           connection == "unconnected",
           set == set_i) %>%
    pull(system_nr)
  
  filtered_data_2 = filtered_data %>%
    filter(connection == "connected" | 
          (connection == "unconnected" &
           system_nr %in% system_nr_unconnected_systems_selected))
  
  # Construct models
  
  full_model = try.different.optimizer.full.model()
  reduced_model = try.different.optimizer.reduced.model()
  null_model = try.different.optimizer.null.model()
  
  # If all the optimisers fail, move on to the next iteration

  if (is.null(full_model) || is.null(reduced_model) || is.null(null_model)) {
    
    cat("This model could not be fitted with any optimiser. The unconnected meta-ecosystems in this iteration were:", 
        system_nr_unconnected_systems_selected, 
        "\n")
    next
    
  }
  
  if(plot_model_residuals_metaecos == TRUE){
    
    # Plot residuals - full model
    
    print(qqnorm(resid(full_model))); print(qqline(resid(full_model)))
    
    #full_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, full_model)
    
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(full_model),
             residuals = resid(full_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_full_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - reduced model
  
    print(qqnorm(resid(reduced_model))); print(qqline(resid(reduced_model)))
    #reduced_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, reduced_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(reduced_model),
             residuals = resid(reduced_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_reduced_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - null model
  
    print(qqnorm(resid(null_model))); print(qqline(resid(null_model)))
    #null_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, null_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(null_model),
             residuals = resid(null_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_null_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  }
  
  # Give model statistics

  model_stats_full = compute.model.stats(full_model,
                                         null_model,
                                         "mixed_model")
  
  model_stats_reduced = compute.model.stats(reduced_model,
                                            null_model,
                                            "mixed_model")
  
  # Save model statistics
  
  iterated_results_table = fill.results.table(iterated_results_table,
                                              response_variable_selected,
                                              metaecosystem_type_selected,
                                              model_stats_full,
                                              model_stats_reduced)
  
  iterated_results_table$set[nrow(iterated_results_table)] = set_i
  
  iterated_results_table$system_nr_unconnected_systems[nrow(iterated_results_table)] = 
  paste(system_nr_unconnected_systems_selected, collapse = " ")
  
}
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: nlminbwrap "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: optimx  (L-BFGS-B)"
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "

 
 
 

Full vs null model

P-value of the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_full),
           p_value = median(iterated_results_table$p_full),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value   evidence
## 1     -8.1   0.002 *** strong
ΔAIC and p-value distributions of the comparison between full and null models
# --- FULL VS NULL MODEL - SHOW ΔAIC & P VALUE DISTRIBUTIONS --- #

hist(iterated_results_table$ΔAIC_full, main = "Distribution of ΔAIC of the full model.") 

hist(iterated_results_table$p_full, main = "Distribution of p-values of the full model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_full) %>%
  arrange(ΔAIC_full)
##     system_nr_unconnected_systems  ΔAIC_full
## 1        1001 1010 1012 1018 1024 -11.383343
## 2        1002 1010 1011 1018 1024 -11.328115
## 3        1003 1010 1012 1016 1024 -11.174864
## 4        1003 1010 1014 1016 1022 -10.933920
## 5        1004 1010 1013 1016 1022 -10.933184
## 6        1004 1010 1011 1018 1022 -10.805806
## 7        1001 1010 1014 1018 1022 -10.797472
## 8        1002 1010 1013 1016 1024 -10.548428
## 9        1001 1009 1012 1018 1025 -10.519043
## 10       1002 1009 1011 1018 1025 -10.395574
## 11       1003 1009 1012 1016 1025 -10.240548
## 12       1004 1007 1011 1018 1025 -10.041854
## 13       1005 1009 1011 1018 1022  -9.949156
## 14       1001 1007 1014 1018 1025  -9.882950
## 15       1004 1007 1013 1016 1025  -9.879992
## 16       1003 1007 1014 1016 1025  -9.859963
## 17       1001 1010 1013 1019 1022  -9.818651
## 18       1005 1006 1012 1018 1024  -9.793929
## 19       1005 1009 1012 1018 1021  -9.789922
## 20       1003 1010 1011 1019 1022  -9.755006
## 21       1002 1006 1015 1018 1024  -9.738514
## 22       1003 1007 1011 1019 1025  -9.687114
## 23       1003 1010 1011 1017 1024  -9.643670
## 24       1002 1009 1015 1018 1021  -9.550444
## 25       1002 1009 1013 1016 1025  -9.499003
## 26       1001 1007 1013 1019 1025  -9.485720
## 27       1001 1009 1015 1018 1022  -9.483894
## 28       1003 1006 1012 1019 1025  -9.295254
## 29       1005 1007 1011 1018 1024  -9.286050
## 30       1004 1010 1012 1018 1021  -9.208206
## 31       1001 1010 1013 1017 1024  -9.202064
## 32       1002 1010 1014 1018 1021  -9.166703
## 33       1003 1009 1015 1016 1022  -9.141212
## 34       1001 1007 1015 1018 1024  -9.137349
## 35       1003 1009 1011 1017 1025  -9.118260
## 36       1002 1006 1014 1018 1025  -9.078364
## 37       1005 1009 1013 1016 1022  -9.049262
## 38       1004 1006 1012 1018 1025  -8.961546
## 39       1002 1006 1013 1019 1025  -8.950068
## 40       1004 1010 1012 1016 1023  -8.877905
## 41       1005 1009 1013 1017 1021  -8.873756
## 42       1005 1006 1013 1017 1024  -8.794243
## 43       1001 1008 1012 1019 1025  -8.765010
## 44       1003 1007 1015 1016 1024  -8.763294
## 45       1003 1006 1015 1017 1024  -8.720595
## 46       1003 1009 1015 1017 1021  -8.658542
## 47       1001 1009 1013 1017 1025  -8.647701
## 48       1003 1006 1014 1017 1025  -8.589933
## 49       1002 1008 1011 1019 1025  -8.564721
## 50       1005 1007 1013 1016 1024  -8.482529
## 51       1002 1009 1013 1020 1021  -8.479112
## 52       1003 1009 1012 1020 1021  -8.462213
## 53       1003 1010 1014 1017 1021  -8.448371
## 54       1002 1006 1013 1020 1024  -8.436634
## 55       1003 1010 1012 1019 1021  -8.421830
## 56       1003 1006 1012 1020 1024  -8.346155
## 57       1001 1010 1012 1019 1023  -8.196195
## 58       1002 1010 1013 1019 1021  -8.101075
## 59       1002 1010 1014 1016 1023  -8.081882
## 60       1004 1010 1013 1017 1021  -8.069221
## 61       1004 1008 1012 1016 1025  -8.064654
## 62       1003 1009 1011 1020 1022  -8.019092
## 63       1004 1006 1013 1017 1025  -7.930107
## 64       1002 1008 1014 1016 1025  -7.879461
## 65       1002 1010 1011 1019 1023  -7.678822
## 66       1004 1006 1015 1018 1022  -7.671478
## 67       1001 1009 1013 1020 1022  -7.670189
## 68       1004 1010 1011 1017 1023  -7.544221
## 69       1001 1008 1014 1017 1025  -7.533712
## 70       1005 1006 1014 1018 1022  -7.412862
## 71       1004 1007 1015 1018 1021  -7.391612
## 72       1003 1007 1011 1020 1024  -7.376748
## 73       1001 1010 1014 1017 1023  -7.369967
## 74       1004 1008 1011 1017 1025  -7.349374
## 75       1005 1007 1014 1018 1021  -7.256318
## 76       1005 1009 1012 1016 1023  -7.221756
## 77       1001 1007 1013 1020 1024  -7.162613
## 78       1005 1009 1011 1017 1023  -6.995350
## 79       1003 1006 1015 1019 1022  -6.911660
## 80       1002 1009 1015 1016 1023  -6.905013
## 81       1004 1008 1015 1016 1022  -6.893383
## 82       1004 1007 1015 1016 1023  -6.815311
## 83       1005 1008 1011 1017 1024  -6.674473
## 84       1003 1007 1015 1019 1021  -6.627537
## 85       1005 1008 1012 1016 1024  -6.608582
## 86       1002 1008 1015 1016 1024  -6.598162
## 87       1002 1009 1011 1020 1023  -6.556795
## 88       1001 1008 1015 1019 1022  -6.549127
## 89       1001 1009 1015 1017 1023  -6.497347
## 90       1001 1008 1015 1017 1024  -6.351890
## 91       1002 1008 1011 1020 1024  -6.339936
## 92       1001 1009 1012 1020 1023  -6.327408
## 93       1001 1007 1015 1019 1023  -6.301880
## 94       1002 1008 1015 1019 1021  -6.235505
## 95       1004 1006 1013 1020 1022  -6.187536
## 96       1005 1006 1013 1019 1022  -6.187145
## 97       1003 1006 1014 1020 1022  -6.169508
## 98       1005 1008 1014 1017 1021  -6.148744
## 99       1005 1007 1014 1016 1023  -6.105929
## 100      1004 1008 1015 1017 1021  -6.076797
## 101      1003 1007 1014 1020 1021  -6.068296
## 102      1005 1007 1013 1019 1021  -6.061303
## 103      1002 1006 1015 1019 1023  -6.050462
## 104      1001 1008 1012 1020 1024  -6.019178
## 105      1004 1007 1013 1020 1021  -6.000434
## 106      1005 1008 1014 1016 1022  -5.983552
## 107      1004 1006 1015 1017 1023  -5.974636
## 108      1005 1006 1014 1017 1023  -5.911575
## 109      1002 1008 1014 1020 1021  -5.847354
## 110      1005 1008 1011 1019 1022  -5.714150
## 111      1005 1008 1012 1019 1021  -5.690115
## 112      1002 1006 1014 1020 1023  -5.638152
## 113      1005 1007 1011 1019 1023  -5.620162
## 114      1005 1006 1012 1019 1023  -5.586102
## 115      1004 1008 1012 1020 1021  -5.575066
## 116      1004 1008 1011 1020 1022  -5.555692
## 117      1004 1006 1012 1020 1023  -5.515638
## 118      1004 1007 1011 1020 1023  -5.414948
## 119      1001 1008 1014 1020 1022  -5.183459
## 120      1001 1007 1014 1020 1023  -5.141150

 
 
 

Reduced vs null model

ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_fix),
           p_value = median(iterated_results_table$p_fix),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value    evidence
## 1     -3.2   0.022 ** moderate
ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW ΔAIC & P VALUE --- #

hist(iterated_results_table$ΔAIC_fix, main = "Distribution of ΔAIC of the reduced model.") 

hist(iterated_results_table$p_fix, main = "Distribution of p-values of the reduced model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- REDUCED VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_fix) %>%
  arrange(ΔAIC_fix)
##     system_nr_unconnected_systems     ΔAIC_fix
## 1        1003 1007 1011 1019 1025 -7.523754233
## 2        1001 1008 1012 1019 1025 -7.314805651
## 3        1003 1006 1012 1019 1025 -7.306793129
## 4        1002 1008 1011 1019 1025 -7.166294261
## 5        1001 1007 1013 1019 1025 -7.117128028
## 6        1003 1010 1011 1019 1022 -6.970018830
## 7        1001 1010 1013 1019 1022 -6.852916359
## 8        1002 1006 1013 1019 1025 -6.759631629
## 9        1003 1010 1014 1016 1022 -6.657599460
## 10       1003 1007 1014 1016 1025 -6.352001507
## 11       1001 1010 1014 1018 1022 -6.272371097
## 12       1003 1006 1014 1017 1025 -5.994301035
## 13       1001 1007 1014 1018 1025 -5.954887023
## 14       1001 1010 1012 1018 1024 -5.912371031
## 15       1001 1008 1014 1017 1025 -5.858276956
## 16       1003 1010 1012 1016 1024 -5.837920984
## 17       1003 1010 1012 1019 1021 -5.766613051
## 18       1002 1008 1014 1016 1025 -5.687159431
## 19       1001 1010 1012 1019 1023 -5.663397934
## 20       1003 1010 1011 1017 1024 -5.600466330
## 21       1003 1010 1014 1017 1021 -5.457235261
## 22       1002 1010 1011 1018 1024 -5.364914131
## 23       1002 1006 1014 1018 1025 -5.242368043
## 24       1002 1010 1013 1019 1021 -5.018674880
## 25       1002 1010 1011 1019 1023 -4.981483849
## 26       1001 1010 1013 1017 1024 -4.767363051
## 27       1004 1007 1011 1018 1025 -4.731624383
## 28       1004 1008 1011 1017 1025 -4.636186795
## 29       1001 1010 1014 1017 1023 -4.632341256
## 30       1004 1008 1012 1016 1025 -4.617155038
## 31       1001 1008 1015 1019 1022 -4.605019421
## 32       1003 1006 1015 1019 1022 -4.583597599
## 33       1004 1007 1013 1016 1025 -4.471763813
## 34       1002 1008 1015 1019 1021 -4.445821830
## 35       1005 1006 1012 1018 1024 -4.305088431
## 36       1002 1010 1013 1016 1024 -4.298200774
## 37       1002 1010 1014 1018 1021 -4.287379506
## 38       1003 1006 1015 1017 1024 -4.240755665
## 39       1004 1010 1011 1018 1022 -4.227095947
## 40       1004 1010 1013 1016 1022 -4.194233151
## 41       1003 1007 1015 1019 1021 -4.178771461
## 42       1005 1006 1013 1017 1024 -4.127548336
## 43       1005 1008 1014 1017 1021 -3.937311595
## 44       1005 1008 1012 1019 1021 -3.934527132
## 45       1002 1006 1015 1019 1023 -3.921767818
## 46       1001 1007 1015 1019 1023 -3.888180274
## 47       1004 1006 1012 1018 1025 -3.875292259
## 48       1002 1006 1015 1018 1024 -3.872512881
## 49       1005 1007 1011 1018 1024 -3.871264744
## 50       1005 1008 1011 1019 1022 -3.818678888
## 51       1003 1007 1015 1016 1024 -3.812205658
## 52       1004 1006 1013 1017 1025 -3.801729797
## 53       1001 1007 1015 1018 1024 -3.724868006
## 54       1005 1006 1013 1019 1022 -3.656544618
## 55       1002 1010 1014 1016 1023 -3.613144472
## 56       1005 1008 1011 1017 1024 -3.538379417
## 57       1004 1010 1011 1017 1023 -3.529986617
## 58       1005 1006 1012 1019 1023 -3.484351801
## 59       1004 1010 1013 1017 1021 -3.389801416
## 60       1004 1010 1012 1016 1023 -3.236074575
## 61       1003 1009 1012 1016 1025 -3.212890387
## 62       1005 1007 1013 1019 1021 -3.170933208
## 63       1003 1009 1011 1017 1025 -3.103757385
## 64       1005 1006 1014 1018 1022 -3.099894911
## 65       1005 1008 1014 1016 1022 -3.088592856
## 66       1005 1006 1014 1017 1023 -3.081451108
## 67       1004 1010 1012 1018 1021 -3.080072868
## 68       1005 1007 1011 1019 1023 -3.043525709
## 69       1002 1008 1014 1020 1021 -2.985554092
## 70       1001 1008 1015 1017 1024 -2.978066786
## 71       1005 1008 1012 1016 1024 -2.886891291
## 72       1002 1008 1015 1016 1024 -2.848785200
## 73       1003 1006 1012 1020 1024 -2.826433451
## 74       1005 1007 1013 1016 1024 -2.796105927
## 75       1001 1009 1012 1018 1025 -2.707071018
## 76       1004 1008 1015 1017 1021 -2.655918008
## 77       1003 1007 1011 1020 1024 -2.626371198
## 78       1005 1007 1014 1018 1021 -2.595215047
## 79       1004 1008 1015 1016 1022 -2.578701618
## 80       1002 1008 1011 1020 1024 -2.450200597
## 81       1003 1007 1014 1020 1021 -2.420175355
## 82       1002 1006 1013 1020 1024 -2.368141681
## 83       1002 1009 1011 1018 1025 -2.356191205
## 84       1001 1008 1014 1020 1022 -2.298672528
## 85       1001 1009 1013 1017 1025 -2.243702168
## 86       1003 1006 1014 1020 1022 -2.228850876
## 87       1002 1009 1013 1016 1025 -2.043636792
## 88       1001 1008 1012 1020 1024 -2.014843410
## 89       1004 1007 1015 1016 1023 -2.013007089
## 90       1005 1007 1014 1016 1023 -1.964213652
## 91       1004 1006 1015 1017 1023 -1.919721687
## 92       1002 1006 1014 1020 1023 -1.905534227
## 93       1004 1007 1015 1018 1021 -1.878713520
## 94       1003 1009 1015 1017 1021 -1.843772349
## 95       1001 1007 1013 1020 1024 -1.801784665
## 96       1001 1007 1014 1020 1023 -1.776539218
## 97       1004 1006 1015 1018 1022 -1.651922493
## 98       1004 1008 1012 1020 1021 -1.547329922
## 99       1005 1009 1013 1017 1021 -1.525336622
## 100      1003 1009 1015 1016 1022 -1.432901114
## 101      1004 1008 1011 1020 1022 -1.344454099
## 102      1004 1007 1011 1020 1023 -1.143843444
## 103      1005 1009 1011 1018 1022 -1.008570885
## 104      1004 1007 1013 1020 1021 -0.928139209
## 105      1005 1009 1012 1018 1021 -0.913460220
## 106      1004 1006 1012 1020 1023 -0.780166126
## 107      1005 1009 1011 1017 1023 -0.621169076
## 108      1005 1009 1013 1016 1022 -0.533024758
## 109      1001 1009 1015 1018 1022 -0.526565765
## 110      1002 1009 1015 1018 1021 -0.495332141
## 111      1004 1006 1013 1020 1022 -0.414910456
## 112      1001 1009 1015 1017 1023 -0.290689677
## 113      1003 1009 1012 1020 1021 -0.218960891
## 114      1002 1009 1015 1016 1023 -0.145302006
## 115      1005 1009 1012 1016 1023  0.001398768
## 116      1003 1009 1011 1020 1022  0.107520674
## 117      1002 1009 1013 1020 1021  0.446712002
## 118      1002 1009 1011 1020 1023  0.526843011
## 119      1001 1009 1012 1020 1023  0.639881348
## 120      1001 1009 1013 1020 1022  0.877017195
MM
metaecosystem_type_selected = c("Medium-Medium")

Our first step in the data analysis involves filtering the data to isolate the relevant data. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure we filtered data the right way.

# --- FILTER DATA --- #

filtered_data = ds_metaecosystems %>%
  filter(time_point %in% time_points_model,
         metaecosystem_type %in% metaecosystem_type_selected,
         !is.na(!!sym("total_water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.metaecos.points(filtered_data,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Then, given that we have gathered measurements from the same meta-ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this meta-ecosystem variable. To study the effects of connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat system nr as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). We also include the total water that was added due to evaporation in the microwave and the time point before the first disturbance (baseline). In the syntax of lmer4 the three models look this this:

Full model = response_variable ~connection * scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Reduced model = response_variable ~connection + scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Null model = response_variable ~scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Unconnected meta-ecosystems are made of paired unconnected ecosystems, which are paired randomly. However, how to pair unconnected ecosystems can be done in multiple ways, as unconnected ecosystems did not interact and therefore any combination between ecosystems would be arbitrary. To make sure that the random combination we selected did not bias our results, we run all the possible combinations of ecosystems constituting unconnected meta-ecosystems. The ecosystem combinations are into the objects unconnected_combinations_sets (Data > Meta-ecosystems). We therefore compute a p-value for each unconnected ecosystems combination, creating a p-value distribution. We keep as p-value of the comparison the median of such distributions.

Code we used to computed the p-values

 

# --- ADD BASELINES --- #

baselines = ds_metaecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(system_nr,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- PREPARE TO COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

unconnected_combinations_sets_filtered =  unconnected_combinations_sets %>%
  filter(disturbance == disturbance_global_selected,
         metaecosystem_type %in% metaecosystem_type_selected)

n_sets = unconnected_combinations_sets_filtered %>%
  pull(set) %>%
  max()

iterated_results_table = data.frame(Response = as.character(NA),
                                    Levels = as.character(NA),
                                    ΔAIC_full = NA,
                                    p_full = NA,
                                    ΔR2_full = NA,
                                    ΔAIC_fix = NA,
                                    p_fix = NA,
                                    ΔR2_fix = NA,
                                    combination_set = NA,
                                    system_nr_unconnected_systems = as.character(NA)) %>%
  slice(-1)
# --- COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

for (set_i in 1:n_sets) {
  
  # Filter the data to contain all the connected meta-ecosystems and only a subset of unconnected meta-ecosystems
  
  system_nr_unconnected_systems_selected = unconnected_combinations_sets_filtered %>%
    filter(metaecosystem_type %in% metaecosystem_type_selected,
           connection == "unconnected",
           set == set_i) %>%
    pull(system_nr)
  
  filtered_data_2 = filtered_data %>%
    filter(connection == "connected" | 
          (connection == "unconnected" &
           system_nr %in% system_nr_unconnected_systems_selected))
  
  # Construct models
  
  full_model = try.different.optimizer.full.model()
  reduced_model = try.different.optimizer.reduced.model()
  null_model = try.different.optimizer.null.model()
  
  # If all the optimisers fail, move on to the next iteration

  if (is.null(full_model) || is.null(reduced_model) || is.null(null_model)) {
    
    cat("This model could not be fitted with any optimiser. The unconnected meta-ecosystems in this iteration were:", 
        system_nr_unconnected_systems_selected, 
        "\n")
    next
    
  }
  
  if(plot_model_residuals_metaecos == TRUE){
    
    # Plot residuals - full model
    
    print(qqnorm(resid(full_model))); print(qqline(resid(full_model)))
    
    #full_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, full_model)
    
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(full_model),
             residuals = resid(full_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_full_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - reduced model
  
    print(qqnorm(resid(reduced_model))); print(qqline(resid(reduced_model)))
    #reduced_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, reduced_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(reduced_model),
             residuals = resid(reduced_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_reduced_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - null model
  
    print(qqnorm(resid(null_model))); print(qqline(resid(null_model)))
    #null_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, null_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(null_model),
             residuals = resid(null_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_null_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  }
  
  # Give model statistics

  model_stats_full = compute.model.stats(full_model,
                                         null_model,
                                         "mixed_model")
  
  model_stats_reduced = compute.model.stats(reduced_model,
                                            null_model,
                                            "mixed_model")
  
  # Save model statistics
  
  iterated_results_table = fill.results.table(iterated_results_table,
                                              response_variable_selected,
                                              metaecosystem_type_selected,
                                              model_stats_full,
                                              model_stats_reduced)
  
  iterated_results_table$set[nrow(iterated_results_table)] = set_i
  
  iterated_results_table$system_nr_unconnected_systems[nrow(iterated_results_table)] = 
  paste(system_nr_unconnected_systems_selected, collapse = " ")
  
}
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "

 
 
 

Full vs null model

P-value of the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_full),
           p_value = median(iterated_results_table$p_full),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      0.4   0.167     none
ΔAIC and p-value distributions of the comparison between full and null models
# --- FULL VS NULL MODEL - SHOW ΔAIC & P VALUE DISTRIBUTIONS --- #

hist(iterated_results_table$ΔAIC_full, main = "Distribution of ΔAIC of the full model.") 

hist(iterated_results_table$p_full, main = "Distribution of p-values of the full model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_full) %>%
  arrange(ΔAIC_full)
##    system_nr_unconnected_systems  ΔAIC_full
## 1                      1051 1054 -4.2568461
## 2                      1054 1051 -4.2568461
## 3                      1048 1054 -3.1415617
## 4                      1054 1048 -3.1415617
## 5                      1047 1051 -2.8437776
## 6                      1051 1047 -2.8437776
## 7                      1048 1050 -2.5739244
## 8                      1050 1048 -2.5739244
## 9                      1050 1055 -2.2893076
## 10                     1055 1050 -2.2893076
## 11                     1047 1055 -1.2693892
## 12                     1055 1047 -1.2693892
## 13                     1052 1053  0.3690701
## 14                     1053 1052  0.3690701
## 15                     1046 1053  0.4150055
## 16                     1053 1046  0.4150055
## 17                     1049 1053  0.8758528
## 18                     1053 1049  0.8758528
## 19                     1046 1054  0.9534051
## 20                     1054 1046  0.9534051
## 21                     1049 1051  1.5480140
## 22                     1051 1049  1.5480140
## 23                     1048 1052  1.6813026
## 24                     1052 1048  1.6813026
## 25                     1047 1052  1.7657519
## 26                     1052 1047  1.7657519
## 27                     1046 1055  1.8032639
## 28                     1055 1046  1.8032639
## 29                     1049 1050  1.8748924
## 30                     1050 1049  1.8748924

 
 
 

Reduced vs null model

ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_fix),
           p_value = median(iterated_results_table$p_fix),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.8   0.638     none
ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW ΔAIC & P VALUE --- #

hist(iterated_results_table$ΔAIC_fix, main = "Distribution of ΔAIC of the reduced model.") 

hist(iterated_results_table$p_fix, main = "Distribution of p-values of the reduced model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- REDUCED VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_fix) %>%
  arrange(ΔAIC_fix)
##    system_nr_unconnected_systems ΔAIC_fix
## 1                      1049 1053 1.362147
## 2                      1053 1049 1.362147
## 3                      1048 1050 1.424910
## 4                      1050 1048 1.424910
## 5                      1048 1054 1.433922
## 6                      1054 1048 1.433922
## 7                      1049 1051 1.669277
## 8                      1051 1049 1.669277
## 9                      1051 1054 1.683158
## 10                     1054 1051 1.683158
## 11                     1046 1053 1.727628
## 12                     1053 1046 1.727628
## 13                     1047 1051 1.739765
## 14                     1051 1047 1.739765
## 15                     1050 1055 1.778962
## 16                     1055 1050 1.778962
## 17                     1049 1050 1.819666
## 18                     1050 1049 1.819666
## 19                     1047 1055 1.829126
## 20                     1055 1047 1.829126
## 21                     1046 1055 1.848900
## 22                     1055 1046 1.848900
## 23                     1048 1052 1.902618
## 24                     1052 1048 1.902618
## 25                     1052 1053 1.953227
## 26                     1053 1052 1.953227
## 27                     1046 1054 1.966968
## 28                     1054 1046 1.966968
## 29                     1047 1052 1.995053
## 30                     1052 1047 1.995053


Following the initial inspection, we proceed to analyse differences among meta-ecosystems. To make it easier to interpret differences, we decided to construct a model for each comparisons we are interested in, which are: SL (connected vs unconnected) and MM (connected vs unconnected).

Beta

response_variable_selected = "bray_curtis"
metaecosystem_type_selected = c("Medium-Medium",
                                "Small-Large")

Here we want to look at how this meta-ecosystem variable changed across time by plotting its mean ± 95 confidence interval:

plot.metaecos.points(ds_metaecosystems,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Data represented through the single replicates
plot.metaecos.replicates(ds_metaecosystems,
                         metaecosystem_type_selected,
                         response_variable_selected)


SL
metaecosystem_type_selected = c("Small-Large")

Our first step in the data analysis involves filtering the data to isolate the relevant data. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure we filtered data the right way.

# --- FILTER DATA --- #

filtered_data = ds_metaecosystems %>%
  filter(time_point %in% time_points_model,
         metaecosystem_type %in% metaecosystem_type_selected,
         !is.na(!!sym("total_water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.metaecos.points(filtered_data,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Then, given that we have gathered measurements from the same meta-ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this meta-ecosystem variable. To study the effects of connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat system nr as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). We also include the total water that was added due to evaporation in the microwave and the time point before the first disturbance (baseline). In the syntax of lmer4 the three models look this this:

Full model = response_variable ~connection * scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Reduced model = response_variable ~connection + scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Null model = response_variable ~scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Unconnected meta-ecosystems are made of paired unconnected ecosystems, which are paired randomly. However, how to pair unconnected ecosystems can be done in multiple ways, as unconnected ecosystems did not interact and therefore any combination between ecosystems would be arbitrary. To make sure that the random combination we selected did not bias our results, we run all the possible combinations of ecosystems constituting unconnected meta-ecosystems. The ecosystem combinations are into the objects unconnected_combinations_sets (Data > Meta-ecosystems). We therefore compute a p-value for each unconnected ecosystems combination, creating a p-value distribution. We keep as p-value of the comparison the median of such distributions.

Code we used to computed the p-values

 

# --- ADD BASELINES --- #

baselines = ds_metaecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(system_nr,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- PREPARE TO COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

unconnected_combinations_sets_filtered =  unconnected_combinations_sets %>%
  filter(disturbance == disturbance_global_selected,
         metaecosystem_type %in% metaecosystem_type_selected)

n_sets = unconnected_combinations_sets_filtered %>%
  pull(set) %>%
  max()

iterated_results_table = data.frame(Response = as.character(NA),
                                    Levels = as.character(NA),
                                    ΔAIC_full = NA,
                                    p_full = NA,
                                    ΔR2_full = NA,
                                    ΔAIC_fix = NA,
                                    p_fix = NA,
                                    ΔR2_fix = NA,
                                    combination_set = NA,
                                    system_nr_unconnected_systems = as.character(NA)) %>%
  slice(-1)
# --- COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

for (set_i in 1:n_sets) {
  
  # Filter the data to contain all the connected meta-ecosystems and only a subset of unconnected meta-ecosystems
  
  system_nr_unconnected_systems_selected = unconnected_combinations_sets_filtered %>%
    filter(metaecosystem_type %in% metaecosystem_type_selected,
           connection == "unconnected",
           set == set_i) %>%
    pull(system_nr)
  
  filtered_data_2 = filtered_data %>%
    filter(connection == "connected" | 
          (connection == "unconnected" &
           system_nr %in% system_nr_unconnected_systems_selected))
  
  # Construct models
  
  full_model = try.different.optimizer.full.model()
  reduced_model = try.different.optimizer.reduced.model()
  null_model = try.different.optimizer.null.model()
  
  # If all the optimisers fail, move on to the next iteration

  if (is.null(full_model) || is.null(reduced_model) || is.null(null_model)) {
    
    cat("This model could not be fitted with any optimiser. The unconnected meta-ecosystems in this iteration were:", 
        system_nr_unconnected_systems_selected, 
        "\n")
    next
    
  }
  
  if(plot_model_residuals_metaecos == TRUE){
    
    # Plot residuals - full model
    
    print(qqnorm(resid(full_model))); print(qqline(resid(full_model)))
    
    #full_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, full_model)
    
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(full_model),
             residuals = resid(full_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_full_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - reduced model
  
    print(qqnorm(resid(reduced_model))); print(qqline(resid(reduced_model)))
    #reduced_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, reduced_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(reduced_model),
             residuals = resid(reduced_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_reduced_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - null model
  
    print(qqnorm(resid(null_model))); print(qqline(resid(null_model)))
    #null_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, null_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(null_model),
             residuals = resid(null_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_null_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  }
  
  # Give model statistics

  model_stats_full = compute.model.stats(full_model,
                                         null_model,
                                         "mixed_model")
  
  model_stats_reduced = compute.model.stats(reduced_model,
                                            null_model,
                                            "mixed_model")
  
  # Save model statistics
  
  iterated_results_table = fill.results.table(iterated_results_table,
                                              response_variable_selected,
                                              metaecosystem_type_selected,
                                              model_stats_full,
                                              model_stats_reduced)
  
  iterated_results_table$set[nrow(iterated_results_table)] = set_i
  
  iterated_results_table$system_nr_unconnected_systems[nrow(iterated_results_table)] = 
  paste(system_nr_unconnected_systems_selected, collapse = " ")
  
}
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: optimx  (L-BFGS-B)"
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: optimx  (L-BFGS-B)"
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: Nelder_Mead "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "

 
 
 

Full vs null model

P-value of the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_full),
           p_value = median(iterated_results_table$p_full),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value         evidence
## 1    -13.5 < 0.001 **** very strong
ΔAIC and p-value distributions of the comparison between full and null models
# --- FULL VS NULL MODEL - SHOW ΔAIC & P VALUE DISTRIBUTIONS --- #

hist(iterated_results_table$ΔAIC_full, main = "Distribution of ΔAIC of the full model.") 

hist(iterated_results_table$p_full, main = "Distribution of p-values of the full model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_full) %>%
  arrange(ΔAIC_full)
##     system_nr_unconnected_systems  ΔAIC_full
## 1        1005 1007 1011 1018 1024 -19.868901
## 2        1005 1008 1011 1017 1024 -18.810536
## 3        1003 1007 1011 1020 1024 -18.800952
## 4        1005 1006 1012 1018 1024 -18.531762
## 5        1005 1006 1013 1017 1024 -18.156957
## 6        1002 1008 1011 1020 1024 -17.928143
## 7        1002 1010 1011 1018 1024 -17.776999
## 8        1003 1010 1011 1017 1024 -17.468673
## 9        1002 1006 1013 1020 1024 -17.285922
## 10       1005 1007 1013 1016 1024 -17.262810
## 11       1003 1006 1012 1020 1024 -17.077173
## 12       1005 1008 1012 1016 1024 -17.060543
## 13       1001 1007 1013 1020 1024 -16.775372
## 14       1002 1006 1015 1018 1024 -16.694557
## 15       1001 1007 1015 1018 1024 -16.677117
## 16       1005 1007 1011 1019 1023 -16.587387
## 17       1005 1007 1013 1019 1021 -16.352645
## 18       1003 1007 1015 1016 1024 -16.268515
## 19       1001 1008 1012 1020 1024 -16.211178
## 20       1005 1006 1012 1019 1023 -16.107655
## 21       1005 1008 1012 1019 1021 -16.014871
## 22       1001 1010 1012 1018 1024 -15.983813
## 23       1003 1006 1015 1017 1024 -15.953119
## 24       1003 1010 1012 1016 1024 -15.706239
## 25       1002 1008 1015 1016 1024 -15.612957
## 26       1005 1008 1011 1019 1022 -15.539390
## 27       1002 1010 1013 1016 1024 -15.391378
## 28       1002 1010 1011 1019 1023 -15.388479
## 29       1001 1010 1013 1017 1024 -15.344149
## 30       1002 1006 1015 1019 1023 -15.330564
## 31       1005 1006 1013 1019 1022 -15.273635
## 32       1001 1008 1015 1017 1024 -15.247117
## 33       1005 1009 1011 1018 1022 -15.172346
## 34       1003 1007 1015 1019 1021 -15.115422
## 35       1002 1008 1015 1019 1021 -14.982364
## 36       1005 1009 1011 1017 1023 -14.946169
## 37       1002 1010 1013 1019 1021 -14.921095
## 38       1005 1009 1012 1018 1021 -14.891439
## 39       1003 1010 1012 1019 1021 -14.842129
## 40       1003 1007 1011 1019 1025 -14.789295
## 41       1005 1009 1013 1017 1021 -14.778419
## 42       1003 1010 1011 1019 1022 -14.690961
## 43       1002 1009 1011 1018 1025 -14.653380
## 44       1002 1008 1011 1019 1025 -14.531017
## 45       1003 1009 1011 1020 1022 -14.510780
## 46       1002 1009 1011 1020 1023 -14.451107
## 47       1002 1006 1013 1019 1025 -14.444938
## 48       1002 1009 1013 1020 1021 -14.323230
## 49       1001 1009 1013 1020 1022 -14.066693
## 50       1005 1009 1013 1016 1022 -14.016928
## 51       1003 1009 1012 1020 1021 -14.005396
## 52       1002 1009 1015 1018 1021 -14.000163
## 53       1003 1009 1011 1017 1025 -13.980456
## 54       1001 1009 1012 1018 1025 -13.931415
## 55       1003 1006 1015 1019 1022 -13.899859
## 56       1005 1009 1012 1016 1023 -13.897050
## 57       1001 1009 1015 1018 1022 -13.853938
## 58       1001 1007 1013 1019 1025 -13.581925
## 59       1001 1009 1012 1020 1023 -13.534560
## 60       1001 1007 1015 1019 1023 -13.507945
## 61       1003 1009 1015 1017 1021 -13.465717
## 62       1003 1006 1012 1019 1025 -13.453673
## 63       1002 1009 1013 1016 1025 -13.363448
## 64       1003 1009 1012 1016 1025 -13.352101
## 65       1001 1009 1013 1017 1025 -13.319949
## 66       1001 1010 1013 1019 1022 -13.272466
## 67       1003 1009 1015 1016 1022 -13.215507
## 68       1001 1008 1015 1019 1022 -13.159300
## 69       1001 1010 1012 1019 1023 -13.107187
## 70       1001 1008 1012 1019 1025 -13.005214
## 71       1002 1009 1015 1016 1023 -12.961267
## 72       1001 1009 1015 1017 1023 -12.885495
## 73       1005 1007 1014 1018 1021 -12.153624
## 74       1001 1007 1014 1018 1025 -11.795575
## 75       1005 1008 1014 1017 1021 -11.706232
## 76       1005 1006 1014 1018 1022 -11.619793
## 77       1001 1010 1014 1018 1022 -11.565541
## 78       1001 1008 1014 1020 1022 -11.465130
## 79       1005 1008 1014 1016 1022 -11.385869
## 80       1005 1006 1014 1017 1023 -11.379378
## 81       1003 1007 1014 1020 1021 -11.320430
## 82       1002 1008 1014 1020 1021 -11.315958
## 83       1002 1010 1014 1018 1021 -11.219287
## 84       1001 1007 1014 1020 1023 -11.122267
## 85       1005 1007 1014 1016 1023 -11.068054
## 86       1002 1006 1014 1020 1023 -11.003506
## 87       1003 1007 1014 1016 1025 -10.918061
## 88       1002 1006 1014 1018 1025 -10.848804
## 89       1003 1010 1014 1017 1021 -10.810011
## 90       1002 1008 1014 1016 1025 -10.805654
## 91       1001 1008 1014 1017 1025 -10.789959
## 92       1003 1006 1014 1020 1022 -10.751925
## 93       1003 1010 1014 1016 1022 -10.727691
## 94       1001 1010 1014 1017 1023 -10.545335
## 95       1002 1010 1014 1016 1023 -10.312417
## 96       1003 1006 1014 1017 1025 -10.003651
## 97       1004 1010 1011 1017 1023  -9.112803
## 98       1004 1007 1011 1020 1023  -8.998167
## 99       1004 1006 1015 1017 1023  -8.850351
## 100      1004 1007 1011 1018 1025  -8.812782
## 101      1004 1010 1012 1018 1021  -8.746495
## 102      1004 1006 1012 1020 1023  -8.650706
## 103      1004 1007 1015 1018 1021  -8.601730
## 104      1004 1010 1011 1018 1022  -8.528238
## 105      1004 1008 1015 1017 1021  -7.995112
## 106      1004 1010 1013 1017 1021  -7.907758
## 107      1004 1008 1012 1020 1021  -7.867624
## 108      1004 1008 1011 1017 1025  -7.860696
## 109      1004 1006 1012 1018 1025  -7.836200
## 110      1004 1006 1015 1018 1022  -7.822736
## 111      1004 1008 1011 1020 1022  -7.787201
## 112      1004 1006 1013 1017 1025  -7.667775
## 113      1004 1007 1013 1020 1021  -7.617443
## 114      1004 1006 1013 1020 1022  -7.447276
## 115      1004 1010 1012 1016 1023  -7.216149
## 116      1004 1007 1015 1016 1023  -7.099472
## 117      1004 1007 1013 1016 1025  -6.562529
## 118      1004 1008 1012 1016 1025  -6.476283
## 119      1004 1010 1013 1016 1022  -6.335508
## 120      1004 1008 1015 1016 1022  -6.254448

 
 
 

Reduced vs null model

ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_fix),
           p_value = median(iterated_results_table$p_fix),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value   evidence
## 1     -6.9   0.003 *** strong
ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW ΔAIC & P VALUE --- #

hist(iterated_results_table$ΔAIC_fix, main = "Distribution of ΔAIC of the reduced model.") 

hist(iterated_results_table$p_fix, main = "Distribution of p-values of the reduced model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- REDUCED VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_fix) %>%
  arrange(ΔAIC_fix)
##     system_nr_unconnected_systems   ΔAIC_fix
## 1        1005 1007 1011 1018 1024 -12.054810
## 2        1003 1007 1011 1020 1024 -11.803154
## 3        1005 1009 1011 1017 1023 -11.126213
## 4        1005 1008 1011 1017 1024 -11.071078
## 5        1003 1009 1011 1020 1022 -10.802225
## 6        1002 1010 1011 1018 1024 -10.757499
## 7        1003 1009 1011 1017 1025 -10.751161
## 8        1002 1009 1011 1018 1025 -10.736151
## 9        1002 1008 1011 1020 1024 -10.667773
## 10       1005 1009 1011 1018 1022 -10.657811
## 11       1003 1010 1011 1017 1024 -10.609852
## 12       1002 1009 1011 1020 1023 -10.604512
## 13       1002 1006 1013 1020 1024 -10.035626
## 14       1005 1007 1011 1019 1023 -10.018236
## 15       1005 1006 1013 1017 1024  -9.899918
## 16       1002 1006 1015 1019 1023  -9.587994
## 17       1005 1009 1013 1017 1021  -9.471900
## 18       1002 1010 1011 1019 1023  -9.406321
## 19       1002 1009 1013 1020 1021  -9.371688
## 20       1003 1007 1011 1019 1025  -9.345132
## 21       1002 1006 1015 1018 1024  -9.215810
## 22       1005 1007 1013 1016 1024  -8.972046
## 23       1003 1009 1012 1020 1021  -8.905591
## 24       1003 1009 1015 1017 1021  -8.903861
## 25       1005 1009 1012 1018 1021  -8.894043
## 26       1002 1008 1011 1019 1025  -8.877274
## 27       1003 1006 1015 1017 1024  -8.801382
## 28       1002 1009 1015 1018 1021  -8.766463
## 29       1005 1008 1011 1019 1022  -8.753358
## 30       1002 1008 1015 1019 1021  -8.734603
## 31       1005 1006 1012 1018 1024  -8.730925
## 32       1003 1007 1015 1019 1021  -8.707752
## 33       1002 1006 1013 1019 1025  -8.640731
## 34       1003 1010 1011 1019 1022  -8.632574
## 35       1003 1006 1012 1020 1024  -8.609615
## 36       1005 1007 1013 1019 1021  -8.579015
## 37       1002 1009 1013 1016 1025  -8.522420
## 38       1005 1006 1012 1019 1023  -8.471960
## 39       1005 1009 1013 1016 1022  -8.446023
## 40       1002 1010 1013 1019 1021  -8.377684
## 41       1005 1008 1012 1019 1021  -8.318841
## 42       1001 1007 1013 1020 1024  -8.306686
## 43       1001 1009 1013 1020 1022  -8.167377
## 44       1002 1010 1013 1016 1024  -8.129777
## 45       1005 1009 1012 1016 1023  -7.914338
## 46       1001 1009 1013 1017 1025  -7.890079
## 47       1003 1010 1012 1019 1021  -7.790210
## 48       1003 1006 1015 1019 1022  -7.765642
## 49       1005 1006 1013 1019 1022  -7.763462
## 50       1003 1009 1012 1016 1025  -7.565731
## 51       1001 1009 1012 1020 1023  -7.345760
## 52       1001 1010 1013 1017 1024  -7.326482
## 53       1002 1009 1015 1016 1023  -7.242529
## 54       1005 1008 1012 1016 1024  -7.210439
## 55       1003 1007 1015 1016 1024  -7.109512
## 56       1004 1007 1011 1020 1023  -7.055347
## 57       1001 1009 1012 1018 1025  -7.054112
## 58       1003 1009 1015 1016 1022  -7.044866
## 59       1003 1006 1012 1019 1025  -6.958326
## 60       1001 1009 1015 1017 1023  -6.893848
## 61       1002 1008 1015 1016 1024  -6.857085
## 62       1004 1007 1011 1018 1025  -6.714248
## 63       1003 1010 1012 1016 1024  -6.708811
## 64       1001 1008 1012 1020 1024  -6.654756
## 65       1001 1009 1015 1018 1022  -6.630876
## 66       1004 1010 1011 1017 1023  -6.616151
## 67       1001 1007 1015 1018 1024  -6.498557
## 68       1001 1007 1013 1019 1025  -6.497803
## 69       1004 1006 1015 1017 1023  -6.330674
## 70       1001 1008 1015 1017 1024  -6.206119
## 71       1001 1010 1012 1018 1024  -6.064642
## 72       1001 1010 1013 1019 1022  -5.991661
## 73       1004 1007 1015 1018 1021  -5.869095
## 74       1001 1007 1015 1019 1023  -5.821836
## 75       1004 1010 1011 1018 1022  -5.807997
## 76       1004 1006 1012 1020 1023  -5.719828
## 77       1004 1008 1011 1017 1025  -5.564127
## 78       1004 1008 1011 1020 1022  -5.354068
## 79       1004 1008 1015 1017 1021  -5.291104
## 80       1004 1010 1012 1018 1021  -5.275769
## 81       1001 1010 1012 1019 1023  -5.271513
## 82       1001 1008 1015 1019 1022  -5.220998
## 83       1001 1008 1012 1019 1025  -5.138572
## 84       1004 1006 1013 1017 1025  -5.036109
## 85       1004 1007 1013 1020 1021  -4.924594
## 86       1004 1006 1015 1018 1022  -4.896623
## 87       1004 1010 1013 1017 1021  -4.875328
## 88       1004 1008 1012 1020 1021  -4.669094
## 89       1004 1006 1013 1020 1022  -4.643646
## 90       1004 1006 1012 1018 1025  -4.583162
## 91       1004 1007 1015 1016 1023  -4.138863
## 92       1004 1007 1013 1016 1025  -4.084905
## 93       1004 1010 1012 1016 1023  -3.876373
## 94       1004 1010 1013 1016 1022  -3.502969
## 95       1002 1006 1014 1020 1023  -3.003262
## 96       1004 1008 1012 1016 1025  -2.995248
## 97       1002 1006 1014 1018 1025  -2.929535
## 98       1004 1008 1015 1016 1022  -2.804403
## 99       1003 1007 1014 1020 1021  -2.658629
## 100      1005 1007 1014 1018 1021  -2.550593
## 101      1002 1010 1014 1018 1021  -2.521081
## 102      1002 1008 1014 1020 1021  -2.413307
## 103      1005 1006 1014 1017 1023  -2.379781
## 104      1003 1006 1014 1017 1025  -2.292904
## 105      1003 1010 1014 1017 1021  -2.266466
## 106      1003 1006 1014 1020 1022  -2.227059
## 107      1005 1008 1014 1017 1021  -2.205381
## 108      1003 1007 1014 1016 1025  -2.180527
## 109      1001 1007 1014 1018 1025  -2.018480
## 110      1002 1008 1014 1016 1025  -1.998963
## 111      1005 1007 1014 1016 1023  -1.946245
## 112      1005 1006 1014 1018 1022  -1.888324
## 113      1002 1010 1014 1016 1023  -1.852978
## 114      1003 1010 1014 1016 1022  -1.847996
## 115      1001 1007 1014 1020 1023  -1.823960
## 116      1001 1008 1014 1020 1022  -1.789733
## 117      1001 1010 1014 1018 1022  -1.701390
## 118      1005 1008 1014 1016 1022  -1.613748
## 119      1001 1008 1014 1017 1025  -1.576207
## 120      1001 1010 1014 1017 1023  -1.406701
MM
metaecosystem_type_selected = c("Medium-Medium")

Our first step in the data analysis involves filtering the data to isolate the relevant data. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure we filtered data the right way.

# --- FILTER DATA --- #

filtered_data = ds_metaecosystems %>%
  filter(time_point %in% time_points_model,
         metaecosystem_type %in% metaecosystem_type_selected,
         !is.na(!!sym("total_water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.metaecos.points(filtered_data,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Then, given that we have gathered measurements from the same meta-ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this meta-ecosystem variable. To study the effects of connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat system nr as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). We also include the total water that was added due to evaporation in the microwave and the time point before the first disturbance (baseline). In the syntax of lmer4 the three models look this this:

Full model = response_variable ~connection * scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Reduced model = response_variable ~connection + scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Null model = response_variable ~scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Unconnected meta-ecosystems are made of paired unconnected ecosystems, which are paired randomly. However, how to pair unconnected ecosystems can be done in multiple ways, as unconnected ecosystems did not interact and therefore any combination between ecosystems would be arbitrary. To make sure that the random combination we selected did not bias our results, we run all the possible combinations of ecosystems constituting unconnected meta-ecosystems. The ecosystem combinations are into the objects unconnected_combinations_sets (Data > Meta-ecosystems). We therefore compute a p-value for each unconnected ecosystems combination, creating a p-value distribution. We keep as p-value of the comparison the median of such distributions.

Code we used to computed the p-values

 

# --- ADD BASELINES --- #

baselines = ds_metaecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(system_nr,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- PREPARE TO COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

unconnected_combinations_sets_filtered =  unconnected_combinations_sets %>%
  filter(disturbance == disturbance_global_selected,
         metaecosystem_type %in% metaecosystem_type_selected)

n_sets = unconnected_combinations_sets_filtered %>%
  pull(set) %>%
  max()

iterated_results_table = data.frame(Response = as.character(NA),
                                    Levels = as.character(NA),
                                    ΔAIC_full = NA,
                                    p_full = NA,
                                    ΔR2_full = NA,
                                    ΔAIC_fix = NA,
                                    p_fix = NA,
                                    ΔR2_fix = NA,
                                    combination_set = NA,
                                    system_nr_unconnected_systems = as.character(NA)) %>%
  slice(-1)
# --- COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

for (set_i in 1:n_sets) {
  
  # Filter the data to contain all the connected meta-ecosystems and only a subset of unconnected meta-ecosystems
  
  system_nr_unconnected_systems_selected = unconnected_combinations_sets_filtered %>%
    filter(metaecosystem_type %in% metaecosystem_type_selected,
           connection == "unconnected",
           set == set_i) %>%
    pull(system_nr)
  
  filtered_data_2 = filtered_data %>%
    filter(connection == "connected" | 
          (connection == "unconnected" &
           system_nr %in% system_nr_unconnected_systems_selected))
  
  # Construct models
  
  full_model = try.different.optimizer.full.model()
  reduced_model = try.different.optimizer.reduced.model()
  null_model = try.different.optimizer.null.model()
  
  # If all the optimisers fail, move on to the next iteration

  if (is.null(full_model) || is.null(reduced_model) || is.null(null_model)) {
    
    cat("This model could not be fitted with any optimiser. The unconnected meta-ecosystems in this iteration were:", 
        system_nr_unconnected_systems_selected, 
        "\n")
    next
    
  }
  
  if(plot_model_residuals_metaecos == TRUE){
    
    # Plot residuals - full model
    
    print(qqnorm(resid(full_model))); print(qqline(resid(full_model)))
    
    #full_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, full_model)
    
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(full_model),
             residuals = resid(full_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_full_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - reduced model
  
    print(qqnorm(resid(reduced_model))); print(qqline(resid(reduced_model)))
    #reduced_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, reduced_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(reduced_model),
             residuals = resid(reduced_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_reduced_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - null model
  
    print(qqnorm(resid(null_model))); print(qqline(resid(null_model)))
    #null_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, null_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(null_model),
             residuals = resid(null_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_null_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  }
  
  # Give model statistics

  model_stats_full = compute.model.stats(full_model,
                                         null_model,
                                         "mixed_model")
  
  model_stats_reduced = compute.model.stats(reduced_model,
                                            null_model,
                                            "mixed_model")
  
  # Save model statistics
  
  iterated_results_table = fill.results.table(iterated_results_table,
                                              response_variable_selected,
                                              metaecosystem_type_selected,
                                              model_stats_full,
                                              model_stats_reduced)
  
  iterated_results_table$set[nrow(iterated_results_table)] = set_i
  
  iterated_results_table$system_nr_unconnected_systems[nrow(iterated_results_table)] = 
  paste(system_nr_unconnected_systems_selected, collapse = " ")
  
}
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "

 
 
 

Full vs null model

P-value of the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_full),
           p_value = median(iterated_results_table$p_full),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      0.7   0.188     none
ΔAIC and p-value distributions of the comparison between full and null models
# --- FULL VS NULL MODEL - SHOW ΔAIC & P VALUE DISTRIBUTIONS --- #

hist(iterated_results_table$ΔAIC_full, main = "Distribution of ΔAIC of the full model.") 

hist(iterated_results_table$p_full, main = "Distribution of p-values of the full model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_full) %>%
  arrange(ΔAIC_full)
##    system_nr_unconnected_systems  ΔAIC_full
## 1                      1047 1052 -7.0607335
## 2                      1052 1047 -7.0607335
## 3                      1050 1055 -6.8797275
## 4                      1055 1050 -6.8797275
## 5                      1052 1053 -5.7371488
## 6                      1053 1052 -5.7371488
## 7                      1047 1055 -4.9047537
## 8                      1055 1047 -4.9047537
## 9                      1047 1051 -3.1078158
## 10                     1051 1047 -3.1078158
## 11                     1046 1055 -1.1276198
## 12                     1055 1046 -1.1276198
## 13                     1051 1054 -0.7159126
## 14                     1054 1051 -0.7159126
## 15                     1049 1053  0.6570313
## 16                     1053 1049  0.6570313
## 17                     1046 1053  0.8298717
## 18                     1053 1046  0.8298717
## 19                     1048 1050  1.0319298
## 20                     1050 1048  1.0319298
## 21                     1048 1052  1.3554353
## 22                     1052 1048  1.3554353
## 23                     1049 1050  1.6240907
## 24                     1050 1049  1.6240907
## 25                     1046 1054  1.8310059
## 26                     1054 1046  1.8310059
## 27                     1049 1051  1.8319359
## 28                     1051 1049  1.8319359
## 29                     1048 1054  3.1286549
## 30                     1054 1048  3.1286549

 
 
 

Reduced vs null model

ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_fix),
           p_value = median(iterated_results_table$p_fix),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1     -0.7   0.098   * weak
ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW ΔAIC & P VALUE --- #

hist(iterated_results_table$ΔAIC_fix, main = "Distribution of ΔAIC of the reduced model.") 

hist(iterated_results_table$p_fix, main = "Distribution of p-values of the reduced model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- REDUCED VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_fix) %>%
  arrange(ΔAIC_fix)
##    system_nr_unconnected_systems   ΔAIC_fix
## 1                      1047 1052 -9.0420799
## 2                      1052 1047 -9.0420799
## 3                      1052 1053 -7.6293919
## 4                      1053 1052 -7.6293919
## 5                      1047 1055 -5.6355950
## 6                      1055 1047 -5.6355950
## 7                      1047 1051 -3.9563482
## 8                      1051 1047 -3.9563482
## 9                      1049 1053 -1.2713678
## 10                     1053 1049 -1.2713678
## 11                     1050 1055 -1.0400315
## 12                     1055 1050 -1.0400315
## 13                     1051 1054 -0.8225792
## 14                     1054 1051 -0.8225792
## 15                     1046 1053 -0.7316877
## 16                     1053 1046 -0.7316877
## 17                     1048 1052 -0.2472453
## 18                     1052 1048 -0.2472453
## 19                     1046 1055  0.0678831
## 20                     1055 1046  0.0678831
## 21                     1049 1051  0.2381335
## 22                     1051 1049  0.2381335
## 23                     1046 1054  0.8015445
## 24                     1054 1046  0.8015445
## 25                     1049 1050  0.9316284
## 26                     1050 1049  0.9316284
## 27                     1048 1054  1.6906341
## 28                     1054 1048  1.6906341
## 29                     1048 1050  1.8004495
## 30                     1050 1048  1.8004495


Following the initial inspection, we proceed to analyse differences among meta-ecosystems. To make it easier to interpret differences, we decided to construct a model for each comparisons we are interested in, which are: SL (connected vs unconnected) and MM (connected vs unconnected).

Gamma

response_variable_selected = "metaecosystem_richness"
metaecosystem_type_selected = c("Medium-Medium",
                                "Small-Large")

Here we want to look at how this meta-ecosystem variable changed across time by plotting its mean ± 95 confidence interval:

plot.metaecos.points(ds_metaecosystems,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Data represented through the single replicates
plot.metaecos.replicates(ds_metaecosystems,
                         metaecosystem_type_selected,
                         response_variable_selected)


SL
metaecosystem_type_selected = c("Small-Large")

Our first step in the data analysis involves filtering the data to isolate the relevant data. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure we filtered data the right way.

# --- FILTER DATA --- #

filtered_data = ds_metaecosystems %>%
  filter(time_point %in% time_points_model,
         metaecosystem_type %in% metaecosystem_type_selected,
         !is.na(!!sym("total_water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.metaecos.points(filtered_data,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Then, given that we have gathered measurements from the same meta-ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this meta-ecosystem variable. To study the effects of connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat system nr as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). We also include the total water that was added due to evaporation in the microwave and the time point before the first disturbance (baseline). In the syntax of lmer4 the three models look this this:

Full model = response_variable ~connection * scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Reduced model = response_variable ~connection + scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Null model = response_variable ~scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Unconnected meta-ecosystems are made of paired unconnected ecosystems, which are paired randomly. However, how to pair unconnected ecosystems can be done in multiple ways, as unconnected ecosystems did not interact and therefore any combination between ecosystems would be arbitrary. To make sure that the random combination we selected did not bias our results, we run all the possible combinations of ecosystems constituting unconnected meta-ecosystems. The ecosystem combinations are into the objects unconnected_combinations_sets (Data > Meta-ecosystems). We therefore compute a p-value for each unconnected ecosystems combination, creating a p-value distribution. We keep as p-value of the comparison the median of such distributions.

Code we used to computed the p-values

 

# --- ADD BASELINES --- #

baselines = ds_metaecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(system_nr,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- PREPARE TO COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

unconnected_combinations_sets_filtered =  unconnected_combinations_sets %>%
  filter(disturbance == disturbance_global_selected,
         metaecosystem_type %in% metaecosystem_type_selected)

n_sets = unconnected_combinations_sets_filtered %>%
  pull(set) %>%
  max()

iterated_results_table = data.frame(Response = as.character(NA),
                                    Levels = as.character(NA),
                                    ΔAIC_full = NA,
                                    p_full = NA,
                                    ΔR2_full = NA,
                                    ΔAIC_fix = NA,
                                    p_fix = NA,
                                    ΔR2_fix = NA,
                                    combination_set = NA,
                                    system_nr_unconnected_systems = as.character(NA)) %>%
  slice(-1)
# --- COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

for (set_i in 1:n_sets) {
  
  # Filter the data to contain all the connected meta-ecosystems and only a subset of unconnected meta-ecosystems
  
  system_nr_unconnected_systems_selected = unconnected_combinations_sets_filtered %>%
    filter(metaecosystem_type %in% metaecosystem_type_selected,
           connection == "unconnected",
           set == set_i) %>%
    pull(system_nr)
  
  filtered_data_2 = filtered_data %>%
    filter(connection == "connected" | 
          (connection == "unconnected" &
           system_nr %in% system_nr_unconnected_systems_selected))
  
  # Construct models
  
  full_model = try.different.optimizer.full.model()
  reduced_model = try.different.optimizer.reduced.model()
  null_model = try.different.optimizer.null.model()
  
  # If all the optimisers fail, move on to the next iteration

  if (is.null(full_model) || is.null(reduced_model) || is.null(null_model)) {
    
    cat("This model could not be fitted with any optimiser. The unconnected meta-ecosystems in this iteration were:", 
        system_nr_unconnected_systems_selected, 
        "\n")
    next
    
  }
  
  if(plot_model_residuals_metaecos == TRUE){
    
    # Plot residuals - full model
    
    print(qqnorm(resid(full_model))); print(qqline(resid(full_model)))
    
    #full_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, full_model)
    
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(full_model),
             residuals = resid(full_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_full_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - reduced model
  
    print(qqnorm(resid(reduced_model))); print(qqline(resid(reduced_model)))
    #reduced_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, reduced_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(reduced_model),
             residuals = resid(reduced_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_reduced_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - null model
  
    print(qqnorm(resid(null_model))); print(qqline(resid(null_model)))
    #null_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, null_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(null_model),
             residuals = resid(null_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_null_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  }
  
  # Give model statistics

  model_stats_full = compute.model.stats(full_model,
                                         null_model,
                                         "mixed_model")
  
  model_stats_reduced = compute.model.stats(reduced_model,
                                            null_model,
                                            "mixed_model")
  
  # Save model statistics
  
  iterated_results_table = fill.results.table(iterated_results_table,
                                              response_variable_selected,
                                              metaecosystem_type_selected,
                                              model_stats_full,
                                              model_stats_reduced)
  
  iterated_results_table$set[nrow(iterated_results_table)] = set_i
  
  iterated_results_table$system_nr_unconnected_systems[nrow(iterated_results_table)] = 
  paste(system_nr_unconnected_systems_selected, collapse = " ")
  
}
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: optimx  (L-BFGS-B)"
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: optimx  (L-BFGS-B)"
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: nlminbwrap "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: nlminbwrap "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: optimx  (L-BFGS-B)"
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: optimx  (L-BFGS-B)"
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "

 
 
 

Full vs null model

P-value of the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_full),
           p_value = median(iterated_results_table$p_full),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1        1   0.228     none
ΔAIC and p-value distributions of the comparison between full and null models
# --- FULL VS NULL MODEL - SHOW ΔAIC & P VALUE DISTRIBUTIONS --- #

hist(iterated_results_table$ΔAIC_full, main = "Distribution of ΔAIC of the full model.") 

hist(iterated_results_table$p_full, main = "Distribution of p-values of the full model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_full) %>%
  arrange(ΔAIC_full)
##     system_nr_unconnected_systems    ΔAIC_full
## 1        1005 1006 1012 1018 1024 -1.778904826
## 2        1003 1006 1012 1020 1024 -1.718037130
## 3        1004 1006 1012 1018 1025 -1.547129228
## 4        1003 1006 1015 1017 1024 -1.385572293
## 5        1003 1006 1012 1019 1025 -1.264075050
## 6        1005 1006 1013 1017 1024 -1.166808812
## 7        1004 1006 1013 1017 1025 -1.008561113
## 8        1004 1006 1015 1018 1022 -0.944926703
## 9        1004 1010 1012 1018 1021 -0.875111995
## 10       1003 1010 1012 1016 1024 -0.678955036
## 11       1004 1006 1013 1020 1022 -0.618020661
## 12       1004 1008 1015 1017 1021 -0.420708033
## 13       1004 1008 1012 1020 1021 -0.414392196
## 14       1004 1008 1012 1016 1025 -0.373534029
## 15       1005 1006 1012 1019 1023 -0.355240112
## 16       1004 1010 1013 1017 1021 -0.325994676
## 17       1004 1006 1015 1017 1023 -0.315069376
## 18       1004 1006 1012 1020 1023 -0.285816573
## 19       1003 1006 1015 1019 1022 -0.241043607
## 20       1003 1010 1012 1019 1021 -0.200868914
## 21       1004 1007 1015 1018 1021 -0.138404548
## 22       1004 1010 1013 1016 1022 -0.110972007
## 23       1004 1010 1011 1018 1022 -0.054404591
## 24       1004 1008 1015 1016 1022 -0.010609720
## 25       1005 1008 1012 1016 1024 -0.001907889
## 26       1003 1006 1014 1017 1025  0.007503791
## 27       1005 1008 1012 1019 1021  0.009311033
## 28       1003 1009 1012 1020 1021  0.026186592
## 29       1005 1006 1013 1019 1022  0.051672424
## 30       1003 1009 1012 1016 1025  0.053479059
## 31       1005 1009 1012 1018 1021  0.175087994
## 32       1004 1007 1013 1020 1021  0.219802387
## 33       1004 1010 1012 1016 1023  0.276154705
## 34       1005 1006 1014 1017 1023  0.333974941
## 35       1004 1007 1013 1016 1025  0.346289331
## 36       1003 1007 1015 1016 1024  0.358493848
## 37       1003 1009 1015 1017 1021  0.376021815
## 38       1005 1006 1014 1018 1022  0.409040896
## 39       1001 1010 1012 1018 1024  0.423327947
## 40       1003 1007 1015 1019 1021  0.457421385
## 41       1004 1008 1011 1017 1025  0.472731611
## 42       1004 1008 1011 1020 1022  0.514714685
## 43       1005 1009 1013 1017 1021  0.576437111
## 44       1003 1010 1011 1019 1022  0.656637935
## 45       1005 1007 1013 1016 1024  0.665315948
## 46       1004 1007 1011 1018 1025  0.674381115
## 47       1003 1010 1011 1017 1024  0.680584118
## 48       1004 1010 1011 1017 1023  0.781676151
## 49       1004 1007 1015 1016 1023  0.786123228
## 50       1005 1007 1013 1019 1021  0.790934777
## 51       1002 1006 1015 1018 1024  0.791434390
## 52       1005 1008 1014 1017 1021  0.794546798
## 53       1003 1006 1014 1020 1022  0.817179695
## 54       1003 1009 1015 1016 1022  0.856215044
## 55       1001 1008 1012 1019 1025  0.898480697
## 56       1001 1010 1013 1017 1024  0.906499597
## 57       1001 1008 1012 1020 1024  0.945901021
## 58       1002 1006 1013 1020 1024  0.993600522
## 59       1001 1009 1012 1018 1025  1.031619470
## 60       1003 1010 1014 1017 1021  1.038201638
## 61       1003 1010 1014 1016 1022  1.051692128
## 62       1001 1008 1015 1017 1024  1.083552457
## 63       1005 1009 1012 1016 1023  1.096239919
## 64       1005 1009 1013 1016 1022  1.101736624
## 65       1005 1008 1014 1016 1022  1.119014927
## 66       1005 1007 1014 1018 1021  1.125138628
## 67       1003 1007 1011 1020 1024  1.148110566
## 68       1001 1007 1015 1018 1024  1.169035787
## 69       1003 1007 1011 1019 1025  1.177307467
## 70       1003 1007 1014 1016 1025  1.194118362
## 71       1005 1008 1011 1019 1022  1.205594748
## 72       1005 1008 1011 1017 1024  1.292515127
## 73       1001 1010 1012 1019 1023  1.307913875
## 74       1005 1007 1011 1018 1024  1.344736150
## 75       1004 1007 1011 1020 1023  1.360531062
## 76       1005 1007 1014 1016 1023  1.363102937
## 77       1001 1009 1013 1017 1025  1.394059215
## 78       1001 1008 1015 1019 1022  1.434802806
## 79       1001 1007 1013 1020 1024  1.435316966
## 80       1003 1007 1014 1020 1021  1.446790143
## 81       1001 1010 1013 1019 1022  1.447593214
## 82       1001 1008 1014 1017 1025  1.465884494
## 83       1003 1009 1011 1017 1025  1.480973254
## 84       1003 1009 1011 1020 1022  1.493649122
## 85       1002 1009 1013 1020 1021  1.543726361
## 86       1001 1007 1013 1019 1025  1.597028665
## 87       1001 1009 1015 1018 1022  1.618149711
## 88       1002 1009 1015 1018 1021  1.618169224
## 89       1002 1006 1013 1019 1025  1.651233214
## 90       1001 1009 1013 1020 1022  1.652180899
## 91       1005 1009 1011 1018 1022  1.701735381
## 92       1001 1010 1014 1018 1022  1.717711732
## 93       1005 1007 1011 1019 1023  1.739874892
## 94       1001 1007 1014 1018 1025  1.784354975
## 95       1001 1010 1014 1017 1023  1.803646532
## 96       1001 1009 1012 1020 1023  1.805835673
## 97       1001 1007 1015 1019 1023  1.871420898
## 98       1002 1008 1015 1019 1021  1.946531960
## 99       1002 1010 1013 1016 1024  1.959416156
## 100      1002 1009 1013 1016 1025  1.964498415
## 101      1002 1006 1015 1019 1023  1.977253733
## 102      1002 1010 1011 1018 1024  1.978097053
## 103      1002 1008 1015 1016 1024  1.979208725
## 104      1001 1009 1015 1017 1023  2.021416410
## 105      1002 1008 1011 1020 1024  2.094187494
## 106      1001 1008 1014 1020 1022  2.131235905
## 107      1005 1009 1011 1017 1023  2.143312099
## 108      1002 1006 1014 1018 1025  2.144558419
## 109      1002 1009 1011 1018 1025  2.249400597
## 110      1002 1010 1013 1019 1021  2.369644955
## 111      1002 1008 1011 1019 1025  2.420073136
## 112      1001 1007 1014 1020 1023  2.436615704
## 113      1002 1009 1015 1016 1023  2.514484269
## 114      1002 1010 1011 1019 1023  2.613271192
## 115      1002 1009 1011 1020 1023  2.702690385
## 116      1002 1006 1014 1020 1023  2.786732349
## 117      1002 1010 1014 1018 1021  2.911085556
## 118      1002 1008 1014 1020 1021  2.961682219
## 119      1002 1008 1014 1016 1025  3.003137511
## 120      1002 1010 1014 1016 1023  3.214292666

 
 
 

Reduced vs null model

ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_fix),
           p_value = median(iterated_results_table$p_fix),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      0.2   0.175     none
ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW ΔAIC & P VALUE --- #

hist(iterated_results_table$ΔAIC_fix, main = "Distribution of ΔAIC of the reduced model.") 

hist(iterated_results_table$p_fix, main = "Distribution of p-values of the reduced model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- REDUCED VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_fix) %>%
  arrange(ΔAIC_fix)
##     system_nr_unconnected_systems     ΔAIC_fix
## 1        1003 1006 1012 1019 1025 -2.219358013
## 2        1005 1006 1012 1018 1024 -2.059679682
## 3        1005 1006 1012 1019 1023 -1.931806483
## 4        1003 1006 1014 1017 1025 -1.711301720
## 5        1005 1006 1014 1017 1023 -1.650302367
## 6        1005 1006 1013 1017 1024 -1.625578728
## 7        1003 1006 1012 1020 1024 -1.470048283
## 8        1003 1006 1015 1017 1024 -1.415450130
## 9        1005 1006 1014 1018 1022 -1.385085638
## 10       1004 1006 1012 1018 1025 -1.215692566
## 11       1005 1008 1012 1019 1021 -1.191223658
## 12       1005 1006 1013 1019 1022 -1.124034660
## 13       1003 1006 1015 1019 1022 -1.048186281
## 14       1005 1008 1014 1017 1021 -1.016368639
## 15       1003 1010 1012 1016 1024 -0.914151725
## 16       1003 1010 1012 1019 1021 -0.897779891
## 17       1005 1008 1012 1016 1024 -0.813977398
## 18       1005 1008 1014 1016 1022 -0.777597672
## 19       1004 1008 1012 1016 1025 -0.728713791
## 20       1004 1006 1013 1017 1025 -0.715238216
## 21       1003 1006 1014 1020 1022 -0.691714909
## 22       1005 1007 1014 1016 1023 -0.631052544
## 23       1001 1008 1012 1019 1025 -0.587337277
## 24       1005 1007 1014 1018 1021 -0.568638572
## 25       1003 1007 1014 1016 1025 -0.566310438
## 26       1003 1010 1014 1016 1022 -0.564102937
## 27       1004 1006 1015 1017 1023 -0.514753479
## 28       1004 1006 1015 1018 1022 -0.507781873
## 29       1001 1008 1014 1017 1025 -0.494455013
## 30       1003 1010 1014 1017 1021 -0.462026430
## 31       1004 1010 1012 1018 1021 -0.388732541
## 32       1005 1007 1013 1019 1021 -0.366504729
## 33       1004 1006 1012 1020 1023 -0.365342151
## 34       1001 1010 1012 1019 1023 -0.332059098
## 35       1004 1008 1015 1017 1021 -0.307642334
## 36       1004 1010 1012 1016 1023 -0.301104238
## 37       1004 1008 1015 1016 1022 -0.201308571
## 38       1003 1007 1015 1019 1021 -0.196896829
## 39       1001 1010 1014 1017 1023 -0.186114872
## 40       1005 1007 1013 1016 1024 -0.140268470
## 41       1004 1008 1012 1020 1021 -0.120352082
## 42       1001 1010 1012 1018 1024 -0.106250688
## 43       1001 1007 1014 1018 1025 -0.103675499
## 44       1004 1007 1013 1016 1025 -0.078385824
## 45       1001 1010 1014 1018 1022 -0.073719216
## 46       1004 1006 1013 1020 1022 -0.067276983
## 47       1004 1010 1013 1016 1022 -0.050607175
## 48       1004 1007 1015 1018 1021 -0.007607146
## 49       1003 1009 1012 1016 1025 -0.002085895
## 50       1005 1008 1011 1019 1022  0.011887907
## 51       1003 1007 1015 1016 1024  0.014014020
## 52       1003 1010 1011 1019 1022  0.024106329
## 53       1004 1007 1015 1016 1023  0.032018034
## 54       1004 1010 1011 1018 1022  0.052408292
## 55       1004 1010 1013 1017 1021  0.052926251
## 56       1001 1008 1015 1019 1022  0.112776231
## 57       1004 1010 1011 1017 1023  0.128178924
## 58       1005 1007 1011 1019 1023  0.133580369
## 59       1001 1007 1013 1019 1025  0.148012106
## 60       1003 1007 1014 1020 1021  0.150475834
## 61       1005 1009 1012 1016 1023  0.176976521
## 62       1004 1008 1011 1017 1025  0.192771965
## 63       1001 1010 1013 1019 1022  0.208347751
## 64       1001 1010 1013 1017 1024  0.232317142
## 65       1001 1007 1015 1019 1023  0.258989920
## 66       1001 1008 1015 1017 1024  0.273175471
## 67       1003 1007 1011 1019 1025  0.298142709
## 68       1005 1009 1012 1018 1021  0.346079707
## 69       1001 1008 1014 1020 1022  0.346902565
## 70       1002 1006 1014 1018 1025  0.364794589
## 71       1001 1008 1012 1020 1024  0.387886785
## 72       1004 1007 1011 1018 1025  0.392393888
## 73       1004 1007 1013 1020 1021  0.405988440
## 74       1001 1007 1015 1018 1024  0.482890066
## 75       1005 1008 1011 1017 1024  0.486647132
## 76       1002 1006 1013 1019 1025  0.495154043
## 77       1002 1006 1015 1018 1024  0.496310995
## 78       1001 1007 1014 1020 1023  0.500554237
## 79       1003 1010 1011 1017 1024  0.519961102
## 80       1002 1006 1015 1019 1023  0.520191712
## 81       1004 1008 1011 1020 1022  0.539178720
## 82       1005 1009 1013 1017 1021  0.658859305
## 83       1005 1007 1011 1018 1024  0.662592247
## 84       1004 1007 1011 1020 1023  0.702502271
## 85       1003 1009 1012 1020 1021  0.717433884
## 86       1001 1009 1012 1018 1025  0.725538800
## 87       1003 1009 1015 1017 1021  0.740027648
## 88       1005 1009 1013 1016 1022  0.749330936
## 89       1003 1009 1015 1016 1022  0.754624454
## 90       1002 1006 1013 1020 1024  0.804710870
## 91       1001 1007 1013 1020 1024  0.839928174
## 92       1005 1009 1011 1017 1023  0.897932466
## 93       1002 1006 1014 1020 1023  0.899347495
## 94       1001 1009 1013 1017 1025  1.012013654
## 95       1005 1009 1011 1018 1022  1.034052768
## 96       1002 1008 1015 1019 1021  1.063714785
## 97       1001 1009 1015 1017 1023  1.065738034
## 98       1002 1008 1014 1016 1025  1.080267417
## 99       1003 1009 1011 1017 1025  1.084833829
## 100      1003 1007 1011 1020 1024  1.093580225
## 101      1001 1009 1012 1020 1023  1.097526419
## 102      1001 1009 1015 1018 1022  1.180888874
## 103      1002 1010 1013 1016 1024  1.223397671
## 104      1002 1010 1014 1016 1023  1.241595386
## 105      1002 1008 1015 1016 1024  1.265946669
## 106      1002 1010 1011 1019 1023  1.278263577
## 107      1002 1010 1014 1018 1021  1.334858820
## 108      1003 1009 1011 1020 1022  1.345350972
## 109      1002 1010 1013 1019 1021  1.370037816
## 110      1001 1009 1013 1020 1022  1.447562357
## 111      1002 1008 1011 1019 1025  1.452959945
## 112      1002 1008 1014 1020 1021  1.473883808
## 113      1002 1009 1015 1016 1023  1.543179254
## 114      1002 1009 1013 1016 1025  1.611291586
## 115      1002 1010 1011 1018 1024  1.677338893
## 116      1002 1009 1015 1018 1021  1.687888414
## 117      1002 1009 1011 1018 1025  1.827296802
## 118      1002 1009 1013 1020 1021  1.849794733
## 119      1002 1009 1011 1020 1023  1.855236500
## 120      1002 1008 1011 1020 1024  1.885207997
MM
metaecosystem_type_selected = c("Medium-Medium")

Our first step in the data analysis involves filtering the data to isolate the relevant data. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure we filtered data the right way.

# --- FILTER DATA --- #

filtered_data = ds_metaecosystems %>%
  filter(time_point %in% time_points_model,
         metaecosystem_type %in% metaecosystem_type_selected,
         !is.na(!!sym("total_water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.metaecos.points(filtered_data,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Then, given that we have gathered measurements from the same meta-ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this meta-ecosystem variable. To study the effects of connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat system nr as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). We also include the total water that was added due to evaporation in the microwave and the time point before the first disturbance (baseline). In the syntax of lmer4 the three models look this this:

Full model = response_variable ~connection * scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Reduced model = response_variable ~connection + scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Null model = response_variable ~scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Unconnected meta-ecosystems are made of paired unconnected ecosystems, which are paired randomly. However, how to pair unconnected ecosystems can be done in multiple ways, as unconnected ecosystems did not interact and therefore any combination between ecosystems would be arbitrary. To make sure that the random combination we selected did not bias our results, we run all the possible combinations of ecosystems constituting unconnected meta-ecosystems. The ecosystem combinations are into the objects unconnected_combinations_sets (Data > Meta-ecosystems). We therefore compute a p-value for each unconnected ecosystems combination, creating a p-value distribution. We keep as p-value of the comparison the median of such distributions.

Code we used to computed the p-values

 

# --- ADD BASELINES --- #

baselines = ds_metaecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(system_nr,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- PREPARE TO COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

unconnected_combinations_sets_filtered =  unconnected_combinations_sets %>%
  filter(disturbance == disturbance_global_selected,
         metaecosystem_type %in% metaecosystem_type_selected)

n_sets = unconnected_combinations_sets_filtered %>%
  pull(set) %>%
  max()

iterated_results_table = data.frame(Response = as.character(NA),
                                    Levels = as.character(NA),
                                    ΔAIC_full = NA,
                                    p_full = NA,
                                    ΔR2_full = NA,
                                    ΔAIC_fix = NA,
                                    p_fix = NA,
                                    ΔR2_fix = NA,
                                    combination_set = NA,
                                    system_nr_unconnected_systems = as.character(NA)) %>%
  slice(-1)
# --- COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

for (set_i in 1:n_sets) {
  
  # Filter the data to contain all the connected meta-ecosystems and only a subset of unconnected meta-ecosystems
  
  system_nr_unconnected_systems_selected = unconnected_combinations_sets_filtered %>%
    filter(metaecosystem_type %in% metaecosystem_type_selected,
           connection == "unconnected",
           set == set_i) %>%
    pull(system_nr)
  
  filtered_data_2 = filtered_data %>%
    filter(connection == "connected" | 
          (connection == "unconnected" &
           system_nr %in% system_nr_unconnected_systems_selected))
  
  # Construct models
  
  full_model = try.different.optimizer.full.model()
  reduced_model = try.different.optimizer.reduced.model()
  null_model = try.different.optimizer.null.model()
  
  # If all the optimisers fail, move on to the next iteration

  if (is.null(full_model) || is.null(reduced_model) || is.null(null_model)) {
    
    cat("This model could not be fitted with any optimiser. The unconnected meta-ecosystems in this iteration were:", 
        system_nr_unconnected_systems_selected, 
        "\n")
    next
    
  }
  
  if(plot_model_residuals_metaecos == TRUE){
    
    # Plot residuals - full model
    
    print(qqnorm(resid(full_model))); print(qqline(resid(full_model)))
    
    #full_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, full_model)
    
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(full_model),
             residuals = resid(full_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_full_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - reduced model
  
    print(qqnorm(resid(reduced_model))); print(qqline(resid(reduced_model)))
    #reduced_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, reduced_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(reduced_model),
             residuals = resid(reduced_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_reduced_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - null model
  
    print(qqnorm(resid(null_model))); print(qqline(resid(null_model)))
    #null_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, null_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(null_model),
             residuals = resid(null_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_null_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  }
  
  # Give model statistics

  model_stats_full = compute.model.stats(full_model,
                                         null_model,
                                         "mixed_model")
  
  model_stats_reduced = compute.model.stats(reduced_model,
                                            null_model,
                                            "mixed_model")
  
  # Save model statistics
  
  iterated_results_table = fill.results.table(iterated_results_table,
                                              response_variable_selected,
                                              metaecosystem_type_selected,
                                              model_stats_full,
                                              model_stats_reduced)
  
  iterated_results_table$set[nrow(iterated_results_table)] = set_i
  
  iterated_results_table$system_nr_unconnected_systems[nrow(iterated_results_table)] = 
  paste(system_nr_unconnected_systems_selected, collapse = " ")
  
}
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "

 
 
 

Full vs null model

P-value of the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_full),
           p_value = median(iterated_results_table$p_full),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.8   0.336     none
ΔAIC and p-value distributions of the comparison between full and null models
# --- FULL VS NULL MODEL - SHOW ΔAIC & P VALUE DISTRIBUTIONS --- #

hist(iterated_results_table$ΔAIC_full, main = "Distribution of ΔAIC of the full model.") 

hist(iterated_results_table$p_full, main = "Distribution of p-values of the full model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_full) %>%
  arrange(ΔAIC_full)
##    system_nr_unconnected_systems    ΔAIC_full
## 1                      1048 1052 -1.475403182
## 2                      1052 1048 -1.475403182
## 3                      1052 1053  0.003672664
## 4                      1053 1052  0.003672664
## 5                      1048 1050  0.058504809
## 6                      1050 1048  0.058504809
## 7                      1047 1052  0.433427147
## 8                      1052 1047  0.433427147
## 9                      1046 1053  0.867464578
## 10                     1053 1046  0.867464578
## 11                     1047 1051  1.209882576
## 12                     1051 1047  1.209882576
## 13                     1050 1055  1.393616601
## 14                     1055 1050  1.393616601
## 15                     1046 1055  1.817874264
## 16                     1055 1046  1.817874264
## 17                     1046 1054  1.826880301
## 18                     1054 1046  1.826880301
## 19                     1048 1054  1.986688934
## 20                     1054 1048  1.986688934
## 21                     1047 1055  1.994237408
## 22                     1055 1047  1.994237408
## 23                     1051 1054  2.144335580
## 24                     1054 1051  2.144335580
## 25                     1049 1051  2.487241386
## 26                     1051 1049  2.487241386
## 27                     1049 1053  2.495267601
## 28                     1053 1049  2.495267601
## 29                     1049 1050  2.556965452
## 30                     1050 1049  2.556965452

 
 
 

Reduced vs null model

ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_fix),
           p_value = median(iterated_results_table$p_fix),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      0.2   0.178     none
ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW ΔAIC & P VALUE --- #

hist(iterated_results_table$ΔAIC_fix, main = "Distribution of ΔAIC of the reduced model.") 

hist(iterated_results_table$p_fix, main = "Distribution of p-values of the reduced model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- REDUCED VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_fix) %>%
  arrange(ΔAIC_fix)
##    system_nr_unconnected_systems   ΔAIC_fix
## 1                      1052 1053 -1.8955591
## 2                      1053 1052 -1.8955591
## 3                      1046 1053 -0.6712230
## 4                      1053 1046 -0.6712230
## 5                      1050 1055 -0.6037116
## 6                      1055 1050 -0.6037116
## 7                      1047 1051 -0.5579459
## 8                      1051 1047 -0.5579459
## 9                      1048 1050 -0.3193849
## 10                     1050 1048 -0.3193849
## 11                     1048 1052  0.1233223
## 12                     1052 1048  0.1233223
## 13                     1047 1052  0.1234953
## 14                     1052 1047  0.1234953
## 15                     1047 1055  0.1834023
## 16                     1055 1047  0.1834023
## 17                     1051 1054  0.2683769
## 18                     1054 1051  0.2683769
## 19                     1048 1054  0.3686785
## 20                     1054 1048  0.3686785
## 21                     1046 1055  0.4611048
## 22                     1055 1046  0.4611048
## 23                     1049 1053  0.6697885
## 24                     1053 1049  0.6697885
## 25                     1049 1051  0.9131296
## 26                     1051 1049  0.9131296
## 27                     1049 1050  1.4509424
## 28                     1050 1049  1.4509424
## 29                     1046 1054  1.5654721
## 30                     1054 1046  1.5654721

Biomass

response_variable_selected = "total_metaecosystem_bioarea_mm2"
metaecosystem_type_selected = c("Medium-Medium",
                                "Small-Large")

Here we want to look at how this meta-ecosystem variable changed across time by plotting its mean ± 95 confidence interval:

plot.metaecos.points(ds_metaecosystems,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Data represented through the single replicates
plot.metaecos.replicates(ds_metaecosystems,
                         metaecosystem_type_selected,
                         response_variable_selected)



Following the initial inspection, we proceed to analyse differences among meta-ecosystems. To make it easier to interpret differences, we decided to construct a model for each comparisons we are interested in, which are: SL (connected vs unconnected) and MM (connected vs unconnected).

SL
metaecosystem_type_selected = c("Small-Large")

Our first step in the data analysis involves filtering the data to isolate the relevant data. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure we filtered data the right way.

# --- FILTER DATA --- #

filtered_data = ds_metaecosystems %>%
  filter(time_point %in% time_points_model,
         metaecosystem_type %in% metaecosystem_type_selected,
         !is.na(!!sym("total_water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.metaecos.points(filtered_data,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Then, given that we have gathered measurements from the same meta-ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this meta-ecosystem variable. To study the effects of connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat system nr as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). We also include the total water that was added due to evaporation in the microwave and the time point before the first disturbance (baseline). In the syntax of lmer4 the three models look this this:

Full model = response_variable ~connection * scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Reduced model = response_variable ~connection + scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Null model = response_variable ~scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Unconnected meta-ecosystems are made of paired unconnected ecosystems, which are paired randomly. However, how to pair unconnected ecosystems can be done in multiple ways, as unconnected ecosystems did not interact and therefore any combination between ecosystems would be arbitrary. To make sure that the random combination we selected did not bias our results, we run all the possible combinations of ecosystems constituting unconnected meta-ecosystems. The ecosystem combinations are into the objects unconnected_combinations_sets (Data > Meta-ecosystems). We therefore compute a p-value for each unconnected ecosystems combination, creating a p-value distribution. We keep as p-value of the comparison the median of such distributions.

Code we used to computed the p-values

 

# --- ADD BASELINES --- #

baselines = ds_metaecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(system_nr,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- PREPARE TO COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

unconnected_combinations_sets_filtered =  unconnected_combinations_sets %>%
  filter(disturbance == disturbance_global_selected,
         metaecosystem_type %in% metaecosystem_type_selected)

n_sets = unconnected_combinations_sets_filtered %>%
  pull(set) %>%
  max()

iterated_results_table = data.frame(Response = as.character(NA),
                                    Levels = as.character(NA),
                                    ΔAIC_full = NA,
                                    p_full = NA,
                                    ΔR2_full = NA,
                                    ΔAIC_fix = NA,
                                    p_fix = NA,
                                    ΔR2_fix = NA,
                                    combination_set = NA,
                                    system_nr_unconnected_systems = as.character(NA)) %>%
  slice(-1)
# --- COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

for (set_i in 1:n_sets) {
  
  # Filter the data to contain all the connected meta-ecosystems and only a subset of unconnected meta-ecosystems
  
  system_nr_unconnected_systems_selected = unconnected_combinations_sets_filtered %>%
    filter(metaecosystem_type %in% metaecosystem_type_selected,
           connection == "unconnected",
           set == set_i) %>%
    pull(system_nr)
  
  filtered_data_2 = filtered_data %>%
    filter(connection == "connected" | 
          (connection == "unconnected" &
           system_nr %in% system_nr_unconnected_systems_selected))
  
  # Construct models
  
  full_model = try.different.optimizer.full.model()
  reduced_model = try.different.optimizer.reduced.model()
  null_model = try.different.optimizer.null.model()
  
  # If all the optimisers fail, move on to the next iteration

  if (is.null(full_model) || is.null(reduced_model) || is.null(null_model)) {
    
    cat("This model could not be fitted with any optimiser. The unconnected meta-ecosystems in this iteration were:", 
        system_nr_unconnected_systems_selected, 
        "\n")
    next
    
  }
  
  if(plot_model_residuals_metaecos == TRUE){
    
    # Plot residuals - full model
    
    print(qqnorm(resid(full_model))); print(qqline(resid(full_model)))
    
    #full_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, full_model)
    
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(full_model),
             residuals = resid(full_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_full_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - reduced model
  
    print(qqnorm(resid(reduced_model))); print(qqline(resid(reduced_model)))
    #reduced_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, reduced_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(reduced_model),
             residuals = resid(reduced_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_reduced_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - null model
  
    print(qqnorm(resid(null_model))); print(qqline(resid(null_model)))
    #null_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, null_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(null_model),
             residuals = resid(null_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_null_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  }
  
  # Give model statistics

  model_stats_full = compute.model.stats(full_model,
                                         null_model,
                                         "mixed_model")
  
  model_stats_reduced = compute.model.stats(reduced_model,
                                            null_model,
                                            "mixed_model")
  
  # Save model statistics
  
  iterated_results_table = fill.results.table(iterated_results_table,
                                              response_variable_selected,
                                              metaecosystem_type_selected,
                                              model_stats_full,
                                              model_stats_reduced)
  
  iterated_results_table$set[nrow(iterated_results_table)] = set_i
  
  iterated_results_table$system_nr_unconnected_systems[nrow(iterated_results_table)] = 
  paste(system_nr_unconnected_systems_selected, collapse = " ")
  
}
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "

 
 
 

Full vs null model

P-value of the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_full),
           p_value = median(iterated_results_table$p_full),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      0.2   0.149     none
ΔAIC and p-value distributions of the comparison between full and null models
# --- FULL VS NULL MODEL - SHOW ΔAIC & P VALUE DISTRIBUTIONS --- #

hist(iterated_results_table$ΔAIC_full, main = "Distribution of ΔAIC of the full model.") 

hist(iterated_results_table$p_full, main = "Distribution of p-values of the full model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_full) %>%
  arrange(ΔAIC_full)
##     system_nr_unconnected_systems     ΔAIC_full
## 1        1001 1009 1012 1018 1025 -0.2683468225
## 2        1001 1008 1012 1019 1025 -0.2454554939
## 3        1003 1009 1012 1016 1025 -0.2084818604
## 4        1003 1006 1012 1019 1025 -0.1638806050
## 5        1001 1008 1012 1020 1024 -0.1099938438
## 6        1003 1009 1011 1017 1025 -0.0987884114
## 7        1003 1009 1012 1020 1021 -0.0721910535
## 8        1001 1008 1014 1017 1025 -0.0553092234
## 9        1001 1008 1015 1019 1022 -0.0512412726
## 10       1001 1009 1012 1020 1023 -0.0499965654
## 11       1001 1009 1015 1018 1022 -0.0299693819
## 12       1003 1009 1015 1017 1021 -0.0279557551
## 13       1003 1007 1011 1019 1025 -0.0173031011
## 14       1003 1006 1015 1019 1022 -0.0170268418
## 15       1003 1009 1015 1016 1022 -0.0056082635
## 16       1005 1008 1012 1019 1021 -0.0048332039
## 17       1002 1009 1011 1018 1025 -0.0004212474
## 18       1005 1009 1012 1018 1021  0.0018432505
## 19       1002 1008 1015 1019 1021  0.0030855825
## 20       1002 1008 1011 1019 1025  0.0041406399
## 21       1003 1007 1015 1019 1021  0.0108962162
## 22       1005 1008 1012 1016 1024  0.0177898111
## 23       1001 1008 1015 1017 1024  0.0214037646
## 24       1002 1009 1015 1018 1021  0.0337086996
## 25       1003 1006 1014 1017 1025  0.0346624703
## 26       1003 1009 1011 1020 1022  0.0381533916
## 27       1001 1010 1012 1018 1024  0.0506890914
## 28       1003 1006 1012 1020 1024  0.0517535213
## 29       1003 1010 1012 1019 1021  0.0525448504
## 30       1002 1008 1014 1016 1025  0.0586825316
## 31       1001 1007 1014 1018 1025  0.0657920723
## 32       1001 1009 1015 1017 1023  0.0730983414
## 33       1005 1009 1012 1016 1023  0.0820554287
## 34       1001 1008 1014 1020 1022  0.0860331083
## 35       1003 1010 1012 1016 1024  0.0929643618
## 36       1003 1007 1014 1016 1025  0.0932894741
## 37       1003 1006 1015 1017 1024  0.0968529116
## 38       1005 1008 1011 1017 1024  0.0971863756
## 39       1005 1008 1011 1019 1022  0.0991505125
## 40       1005 1009 1011 1018 1022  0.1125744073
## 41       1001 1010 1012 1019 1023  0.1140497254
## 42       1005 1006 1012 1018 1024  0.1148109878
## 43       1001 1007 1015 1018 1024  0.1213672481
## 44       1002 1006 1014 1018 1025  0.1239664036
## 45       1003 1010 1011 1019 1022  0.1302450955
## 46       1002 1008 1015 1016 1024  0.1325186375
## 47       1001 1007 1015 1019 1023  0.1416835828
## 48       1002 1008 1011 1020 1024  0.1438621768
## 49       1005 1008 1014 1017 1021  0.1459421379
## 50       1003 1007 1015 1016 1024  0.1486564756
## 51       1003 1010 1011 1017 1024  0.1487282051
## 52       1005 1006 1012 1019 1023  0.1542102863
## 53       1005 1008 1014 1016 1022  0.1581073437
## 54       1005 1009 1011 1017 1023  0.1690615383
## 55       1003 1006 1014 1020 1022  0.1694577248
## 56       1003 1007 1011 1020 1024  0.1717822595
## 57       1002 1006 1015 1018 1024  0.1745939468
## 58       1002 1008 1014 1020 1021  0.1749037263
## 59       1002 1006 1015 1019 1023  0.1808814100
## 60       1002 1009 1015 1016 1023  0.1844881895
## 61       1004 1008 1012 1016 1025  0.1948745221
## 62       1002 1009 1011 1020 1023  0.2086995377
## 63       1003 1007 1014 1020 1021  0.2145802194
## 64       1001 1010 1014 1018 1022  0.2162895407
## 65       1003 1010 1014 1017 1021  0.2223999197
## 66       1004 1006 1012 1018 1025  0.2248748144
## 67       1004 1008 1015 1017 1021  0.2286229572
## 68       1003 1010 1014 1016 1022  0.2309148725
## 69       1005 1006 1014 1018 1022  0.2349267578
## 70       1004 1008 1015 1016 1022  0.2419978151
## 71       1005 1007 1011 1018 1024  0.2425460381
## 72       1004 1006 1015 1018 1022  0.2463745510
## 73       1002 1010 1011 1018 1024  0.2563204004
## 74       1005 1007 1014 1018 1021  0.2847099526
## 75       1005 1007 1011 1019 1023  0.2866743792
## 76       1004 1008 1011 1017 1025  0.2879210975
## 77       1004 1007 1015 1018 1021  0.2913289426
## 78       1004 1008 1012 1020 1021  0.2979974140
## 79       1002 1010 1014 1018 1021  0.3049729590
## 80       1002 1010 1011 1019 1023  0.3103581812
## 81       1001 1010 1014 1017 1023  0.3522940304
## 82       1004 1007 1011 1018 1025  0.3553969485
## 83       1001 1009 1013 1017 1025  0.3579632057
## 84       1001 1007 1014 1020 1023  0.3618545769
## 85       1005 1006 1014 1017 1023  0.3758791146
## 86       1004 1008 1011 1020 1022  0.3841110898
## 87       1004 1010 1012 1018 1021  0.3889350822
## 88       1004 1006 1015 1017 1023  0.4060196860
## 89       1002 1006 1014 1020 1023  0.4197892202
## 90       1005 1007 1014 1016 1023  0.4426687234
## 91       1004 1010 1011 1018 1022  0.4453434887
## 92       1001 1009 1013 1020 1022  0.4463930560
## 93       1004 1006 1012 1020 1023  0.4616285894
## 94       1002 1010 1014 1016 1023  0.4668071699
## 95       1004 1007 1015 1016 1023  0.4707332751
## 96       1001 1007 1013 1019 1025  0.4738501769
## 97       1001 1010 1013 1017 1024  0.4818174381
## 98       1004 1010 1012 1016 1023  0.4962512608
## 99       1001 1010 1013 1019 1022  0.5061870346
## 100      1002 1009 1013 1016 1025  0.5198811871
## 101      1005 1009 1013 1016 1022  0.5283602683
## 102      1005 1009 1013 1017 1021  0.5295623824
## 103      1004 1010 1011 1017 1023  0.5480751233
## 104      1001 1007 1013 1020 1024  0.5582233921
## 105      1002 1006 1013 1019 1025  0.5734486267
## 106      1004 1007 1011 1020 1023  0.5828436353
## 107      1005 1006 1013 1017 1024  0.5847651773
## 108      1005 1006 1013 1019 1022  0.5850660366
## 109      1002 1009 1013 1020 1021  0.6010631809
## 110      1005 1007 1013 1016 1024  0.6301339432
## 111      1002 1010 1013 1016 1024  0.6372269987
## 112      1005 1007 1013 1019 1021  0.6387527780
## 113      1002 1010 1013 1019 1021  0.6395254010
## 114      1002 1006 1013 1020 1024  0.6879250699
## 115      1004 1006 1013 1017 1025  0.8439821326
## 116      1004 1010 1013 1016 1022  0.8688078132
## 117      1004 1010 1013 1017 1021  0.8755440867
## 118      1004 1006 1013 1020 1022  0.8887790216
## 119      1004 1007 1013 1016 1025  0.8956529471
## 120      1004 1007 1013 1020 1021  0.9456796479

 
 
 

Reduced vs null model

ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_fix),
           p_value = median(iterated_results_table$p_fix),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1     -1.6   0.057   * weak
ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW ΔAIC & P VALUE --- #

hist(iterated_results_table$ΔAIC_fix, main = "Distribution of ΔAIC of the reduced model.") 

hist(iterated_results_table$p_fix, main = "Distribution of p-values of the reduced model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- REDUCED VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_fix) %>%
  arrange(ΔAIC_fix)
##     system_nr_unconnected_systems  ΔAIC_fix
## 1        1001 1008 1012 1019 1025 -2.182491
## 2        1001 1009 1012 1018 1025 -2.172731
## 3        1003 1009 1012 1016 1025 -2.107717
## 4        1001 1008 1012 1020 1024 -2.102531
## 5        1001 1009 1012 1020 1023 -2.026749
## 6        1003 1006 1012 1019 1025 -2.015332
## 7        1003 1009 1011 1017 1025 -1.990367
## 8        1005 1008 1012 1016 1024 -1.971602
## 9        1003 1009 1012 1020 1021 -1.943598
## 10       1001 1010 1012 1018 1024 -1.938769
## 11       1001 1008 1015 1017 1024 -1.927036
## 12       1005 1008 1012 1019 1021 -1.907384
## 13       1003 1010 1012 1016 1024 -1.896069
## 14       1003 1006 1012 1020 1024 -1.894695
## 15       1002 1008 1011 1019 1025 -1.892851
## 16       1005 1008 1011 1017 1024 -1.891832
## 17       1005 1009 1012 1016 1023 -1.887131
## 18       1001 1008 1015 1019 1022 -1.884560
## 19       1001 1010 1012 1019 1023 -1.876738
## 20       1005 1009 1012 1018 1021 -1.864973
## 21       1003 1010 1012 1019 1021 -1.853563
## 22       1003 1007 1011 1019 1025 -1.853158
## 23       1002 1009 1011 1018 1025 -1.849551
## 24       1001 1009 1015 1017 1023 -1.841241
## 25       1003 1010 1011 1017 1024 -1.839583
## 26       1002 1008 1011 1020 1024 -1.838138
## 27       1005 1006 1012 1018 1024 -1.830593
## 28       1003 1009 1011 1020 1022 -1.822542
## 29       1001 1009 1015 1018 1022 -1.821596
## 30       1003 1009 1015 1017 1021 -1.802862
## 31       1001 1008 1014 1017 1025 -1.798684
## 32       1005 1009 1011 1017 1023 -1.793213
## 33       1002 1008 1015 1016 1024 -1.789985
## 34       1005 1006 1012 1019 1023 -1.788693
## 35       1005 1008 1011 1019 1022 -1.785180
## 36       1003 1009 1015 1016 1022 -1.784588
## 37       1003 1006 1015 1017 1024 -1.781299
## 38       1003 1007 1011 1020 1024 -1.775515
## 39       1002 1008 1015 1019 1021 -1.773676
## 40       1001 1007 1015 1018 1024 -1.772379
## 41       1003 1010 1011 1019 1022 -1.760197
## 42       1003 1006 1015 1019 1022 -1.750785
## 43       1004 1008 1012 1016 1025 -1.749543
## 44       1001 1007 1015 1019 1023 -1.748338
## 45       1002 1009 1011 1020 1023 -1.741951
## 46       1003 1007 1015 1016 1024 -1.737956
## 47       1005 1009 1011 1018 1022 -1.726848
## 48       1003 1007 1015 1019 1021 -1.725151
## 49       1002 1010 1011 1018 1024 -1.715813
## 50       1005 1007 1011 1018 1024 -1.694444
## 51       1002 1009 1015 1016 1023 -1.692816
## 52       1002 1009 1015 1018 1021 -1.692678
## 53       1002 1006 1015 1018 1024 -1.669624
## 54       1002 1010 1011 1019 1023 -1.660091
## 55       1002 1006 1015 1019 1023 -1.656766
## 56       1004 1008 1011 1017 1025 -1.649427
## 57       1004 1006 1012 1018 1025 -1.645578
## 58       1005 1007 1011 1019 1023 -1.643164
## 59       1004 1008 1012 1020 1021 -1.627684
## 60       1001 1008 1014 1020 1022 -1.619271
## 61       1004 1008 1015 1017 1021 -1.615768
## 62       1001 1009 1013 1017 1025 -1.605184
## 63       1002 1008 1014 1016 1025 -1.603539
## 64       1004 1008 1015 1016 1022 -1.599449
## 65       1003 1006 1014 1017 1025 -1.598682
## 66       1001 1007 1014 1018 1025 -1.588177
## 67       1005 1008 1014 1017 1021 -1.545813
## 68       1003 1007 1014 1016 1025 -1.532989
## 69       1004 1010 1012 1018 1021 -1.532754
## 70       1001 1010 1014 1017 1023 -1.527251
## 71       1004 1008 1011 1020 1022 -1.526116
## 72       1001 1010 1013 1017 1024 -1.516370
## 73       1005 1008 1014 1016 1022 -1.510757
## 74       1004 1006 1015 1018 1022 -1.509596
## 75       1001 1010 1014 1018 1022 -1.505000
## 76       1001 1009 1013 1020 1022 -1.500836
## 77       1004 1010 1012 1016 1023 -1.496412
## 78       1004 1006 1012 1020 1023 -1.495044
## 79       1003 1010 1014 1017 1021 -1.493156
## 80       1004 1007 1011 1018 1025 -1.485052
## 81       1004 1006 1015 1017 1023 -1.483121
## 82       1001 1007 1013 1019 1025 -1.469007
## 83       1004 1007 1015 1018 1021 -1.468101
## 84       1001 1010 1013 1019 1022 -1.467684
## 85       1003 1010 1014 1016 1022 -1.466879
## 86       1002 1008 1014 1020 1021 -1.457733
## 87       1004 1010 1011 1018 1022 -1.448915
## 88       1004 1010 1011 1017 1023 -1.440425
## 89       1002 1006 1014 1018 1025 -1.439584
## 90       1001 1007 1014 1020 1023 -1.438312
## 91       1001 1007 1013 1020 1024 -1.436174
## 92       1003 1006 1014 1020 1022 -1.424139
## 93       1004 1007 1015 1016 1023 -1.421432
## 94       1002 1009 1013 1016 1025 -1.416773
## 95       1005 1009 1013 1017 1021 -1.413995
## 96       1005 1009 1013 1016 1022 -1.412656
## 97       1005 1006 1013 1017 1024 -1.408259
## 98       1005 1006 1014 1017 1023 -1.404935
## 99       1003 1007 1014 1020 1021 -1.390486
## 100      1005 1007 1013 1016 1024 -1.364311
## 101      1004 1007 1011 1020 1023 -1.362773
## 102      1002 1010 1013 1016 1024 -1.362712
## 103      1002 1010 1014 1016 1023 -1.357470
## 104      1005 1006 1014 1018 1022 -1.356888
## 105      1002 1010 1014 1018 1021 -1.346987
## 106      1005 1007 1014 1016 1023 -1.334623
## 107      1005 1006 1013 1019 1022 -1.333759
## 108      1002 1006 1013 1019 1025 -1.329268
## 109      1005 1007 1014 1018 1021 -1.321908
## 110      1002 1009 1013 1020 1021 -1.312449
## 111      1002 1010 1013 1019 1021 -1.310664
## 112      1002 1006 1014 1020 1023 -1.307705
## 113      1002 1006 1013 1020 1024 -1.290937
## 114      1005 1007 1013 1019 1021 -1.285206
## 115      1004 1010 1013 1016 1022 -1.110151
## 116      1004 1010 1013 1017 1021 -1.105946
## 117      1004 1006 1013 1017 1025 -1.104419
## 118      1004 1007 1013 1016 1025 -1.053338
## 119      1004 1006 1013 1020 1022 -1.042303
## 120      1004 1007 1013 1020 1021 -0.990200
MM
metaecosystem_type_selected = c("Medium-Medium")

Our first step in the data analysis involves filtering the data to isolate the relevant data. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure we filtered data the right way.

# --- FILTER DATA --- #

filtered_data = ds_metaecosystems %>%
  filter(time_point %in% time_points_model,
         metaecosystem_type %in% metaecosystem_type_selected,
         !is.na(!!sym("total_water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.metaecos.points(filtered_data,
                     metaecosystem_type_selected,
                     connection_selected,
                     response_variable_selected)

Then, given that we have gathered measurements from the same meta-ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this meta-ecosystem variable. To study the effects of connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat system nr as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). We also include the total water that was added due to evaporation in the microwave and the time point before the first disturbance (baseline). In the syntax of lmer4 the three models look this this:

Full model = response_variable ~connection * scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Reduced model = response_variable ~connection + scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Null model = response_variable ~scale(day) + scale(total_water_addition_ml) * scale(day) + scale(baseline) * scale(day) + (day | system_nr)

Unconnected meta-ecosystems are made of paired unconnected ecosystems, which are paired randomly. However, how to pair unconnected ecosystems can be done in multiple ways, as unconnected ecosystems did not interact and therefore any combination between ecosystems would be arbitrary. To make sure that the random combination we selected did not bias our results, we run all the possible combinations of ecosystems constituting unconnected meta-ecosystems. The ecosystem combinations are into the objects unconnected_combinations_sets (Data > Meta-ecosystems). We therefore compute a p-value for each unconnected ecosystems combination, creating a p-value distribution. We keep as p-value of the comparison the median of such distributions.

Code we used to computed the p-values

 

# --- ADD BASELINES --- #

baselines = ds_metaecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(system_nr,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- PREPARE TO COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

unconnected_combinations_sets_filtered =  unconnected_combinations_sets %>%
  filter(disturbance == disturbance_global_selected,
         metaecosystem_type %in% metaecosystem_type_selected)

n_sets = unconnected_combinations_sets_filtered %>%
  pull(set) %>%
  max()

iterated_results_table = data.frame(Response = as.character(NA),
                                    Levels = as.character(NA),
                                    ΔAIC_full = NA,
                                    p_full = NA,
                                    ΔR2_full = NA,
                                    ΔAIC_fix = NA,
                                    p_fix = NA,
                                    ΔR2_fix = NA,
                                    combination_set = NA,
                                    system_nr_unconnected_systems = as.character(NA)) %>%
  slice(-1)
# --- COMPARE FULL, REDUCED, AND NULL MODEL WHILE RESHUFFLING ECOSYSTEM COMBINATIONS --- #

for (set_i in 1:n_sets) {
  
  # Filter the data to contain all the connected meta-ecosystems and only a subset of unconnected meta-ecosystems
  
  system_nr_unconnected_systems_selected = unconnected_combinations_sets_filtered %>%
    filter(metaecosystem_type %in% metaecosystem_type_selected,
           connection == "unconnected",
           set == set_i) %>%
    pull(system_nr)
  
  filtered_data_2 = filtered_data %>%
    filter(connection == "connected" | 
          (connection == "unconnected" &
           system_nr %in% system_nr_unconnected_systems_selected))
  
  # Construct models
  
  full_model = try.different.optimizer.full.model()
  reduced_model = try.different.optimizer.reduced.model()
  null_model = try.different.optimizer.null.model()
  
  # If all the optimisers fail, move on to the next iteration

  if (is.null(full_model) || is.null(reduced_model) || is.null(null_model)) {
    
    cat("This model could not be fitted with any optimiser. The unconnected meta-ecosystems in this iteration were:", 
        system_nr_unconnected_systems_selected, 
        "\n")
    next
    
  }
  
  if(plot_model_residuals_metaecos == TRUE){
    
    # Plot residuals - full model
    
    print(qqnorm(resid(full_model))); print(qqline(resid(full_model)))
    
    #full_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, full_model)
    
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(full_model),
             residuals = resid(full_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_full_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - reduced model
  
    print(qqnorm(resid(reduced_model))); print(qqline(resid(reduced_model)))
    #reduced_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, reduced_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(reduced_model),
             residuals = resid(reduced_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_reduced_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  
    # Plot residuals - null model
  
    print(qqnorm(resid(null_model))); print(qqline(resid(null_model)))
    #null_model_res_vs_fit[[set_i]] = create.res.vs.fit.metaecos(filtered_data_2, null_model)
    plot = filtered_data_2 %>%
      mutate(predicted = fitted(null_model),
             residuals = resid(null_model)) %>%
      ggplot(aes(x = predicted,
                 y = residuals)) +
      geom_point()
    
    ggsave(here("6_results",
                "residual_plots",
                paste0(disturbance_global_selected,
                       "_disturbance_",
                       gsub(pattern = " ", replacement = "", metaecosystem_type_selected[[1]]),
                       "_",
                       response_variable_selected,
                       "_",
                       set_i,
                       "_null_model.png")), 
           plot = plot, 
           width = 8, 
           height = 6)
  }
  
  # Give model statistics

  model_stats_full = compute.model.stats(full_model,
                                         null_model,
                                         "mixed_model")
  
  model_stats_reduced = compute.model.stats(reduced_model,
                                            null_model,
                                            "mixed_model")
  
  # Save model statistics
  
  iterated_results_table = fill.results.table(iterated_results_table,
                                              response_variable_selected,
                                              metaecosystem_type_selected,
                                              model_stats_full,
                                              model_stats_reduced)
  
  iterated_results_table$set[nrow(iterated_results_table)] = set_i
  
  iterated_results_table$system_nr_unconnected_systems[nrow(iterated_results_table)] = 
  paste(system_nr_unconnected_systems_selected, collapse = " ")
  
}
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "
## [1] "Model successfully fitted with optimizer: bobyqa "

 
 
 

Full vs null model

P-value of the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_full),
           p_value = median(iterated_results_table$p_full),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1     -1.5   0.063   * weak
ΔAIC and p-value distributions of the comparison between full and null models
# --- FULL VS NULL MODEL - SHOW ΔAIC & P VALUE DISTRIBUTIONS --- #

hist(iterated_results_table$ΔAIC_full, main = "Distribution of ΔAIC of the full model.") 

hist(iterated_results_table$p_full, main = "Distribution of p-values of the full model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- FULL VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_full) %>%
  arrange(ΔAIC_full)
##    system_nr_unconnected_systems  ΔAIC_full
## 1                      1050 1055 -3.3008508
## 2                      1055 1050 -3.3008508
## 3                      1048 1050 -2.4229375
## 4                      1050 1048 -2.4229375
## 5                      1051 1054 -2.2350516
## 6                      1054 1051 -2.2350516
## 7                      1052 1053 -1.9741663
## 8                      1053 1052 -1.9741663
## 9                      1048 1052 -1.6944652
## 10                     1052 1048 -1.6944652
## 11                     1049 1050 -1.5989419
## 12                     1050 1049 -1.5989419
## 13                     1046 1055 -1.5320382
## 14                     1055 1046 -1.5320382
## 15                     1049 1051 -1.5179048
## 16                     1051 1049 -1.5179048
## 17                     1047 1051 -1.3170137
## 18                     1051 1047 -1.3170137
## 19                     1046 1053 -1.0203738
## 20                     1053 1046 -1.0203738
## 21                     1047 1052 -0.7897137
## 22                     1052 1047 -0.7897137
## 23                     1046 1054 -0.6788248
## 24                     1054 1046 -0.6788248
## 25                     1047 1055 -0.6405515
## 26                     1055 1047 -0.6405515
## 27                     1048 1054 -0.6336421
## 28                     1054 1048 -0.6336421
## 29                     1049 1053 -0.3993607
## 30                     1053 1049 -0.3993607

 
 
 

Reduced vs null model

ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

data.frame(deltaAIC = median(iterated_results_table$ΔAIC_fix),
           p_value = median(iterated_results_table$p_fix),
           R2 = NA) %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      0.9   0.302     none
ΔAIC and p-value distributions of the comparison between reduced and null models
# --- REDUCED VS NULL MODEL - SHOW ΔAIC & P VALUE --- #

hist(iterated_results_table$ΔAIC_fix, main = "Distribution of ΔAIC of the reduced model.") 

hist(iterated_results_table$p_fix, main = "Distribution of p-values of the reduced model.") 

Unconnected meta-ecosystem numbers produced which AIC in the comparison between full and null model
# --- REDUCED VS NULL MODEL - SHOW WHICH UNCONNECTED META-ECOSYSTEM NUMBER PRODUCD WHICH AIC --- #

iterated_results_table %>% 
  select(system_nr_unconnected_systems,
         ΔAIC_fix) %>%
  arrange(ΔAIC_fix)
##    system_nr_unconnected_systems    ΔAIC_fix
## 1                      1050 1055 -0.08519968
## 2                      1055 1050 -0.08519968
## 3                      1051 1054  0.23007970
## 4                      1054 1051  0.23007970
## 5                      1052 1053  0.29774862
## 6                      1053 1052  0.29774862
## 7                      1048 1050  0.43118230
## 8                      1050 1048  0.43118230
## 9                      1047 1051  0.66001146
## 10                     1051 1047  0.66001146
## 11                     1049 1050  0.67529114
## 12                     1050 1049  0.67529114
## 13                     1046 1053  0.82200249
## 14                     1053 1046  0.82200249
## 15                     1048 1052  0.93568316
## 16                     1052 1048  0.93568316
## 17                     1049 1051  0.98144359
## 18                     1051 1049  0.98144359
## 19                     1046 1055  1.01203992
## 20                     1055 1046  1.01203992
## 21                     1046 1054  1.02180928
## 22                     1054 1046  1.02180928
## 23                     1047 1052  1.14625730
## 24                     1052 1047  1.14625730
## 25                     1048 1054  1.22660330
## 26                     1054 1048  1.22660330
## 27                     1049 1053  1.26054998
## 28                     1053 1049  1.26054998
## 29                     1047 1055  1.30516701
## 30                     1055 1047  1.30516701

All ecosystems

ecosystem_type_selected = c("Small unconnected",
                            "Medium unconnected",
                            "Large unconnected",
                            "Small connected to small",
                            "Small connected to large",
                            "Medium connected to medium",
                            "Large connected to small",
                            "Large connected to large")

BEF

ds_ecosystems %>%
    filter(is.na(species_richness) != TRUE) %>%
    ggplot(aes(x = species_richness,
               y = bioarea_mm2_per_ml)) +
    geom_point() +
    xlim(0, length(protist_species)) +
    labs(x = axis_names$axis_name[axis_names$variable == "species_richness"],
         y = axis_names$axis_name[axis_names$variable == "bioarea_mm2_per_ml"]) + 
    theme_bw() +
    theme(panel.grid.major = element_blank(),
          panel.grid.minor = element_blank(),
          legend.position = legend_position,
          legend.key.width = unit(legend_width_cm, "cm"))

ds_ecosystems %>%
  filter(is.na(shannon) != TRUE) %>%
  ggplot(aes(x = shannon,
             y = bioarea_mm2_per_ml)) +
  geom_point() +
  labs(x = axis_names$axis_name[axis_names$variable == "shannon"],
       y = axis_names$axis_name[axis_names$variable == "bioarea_mm2_per_ml"]) + 
  theme_bw() +
    theme(panel.grid.major = element_blank(),
          panel.grid.minor = element_blank(),
          legend.position = legend_position,
          legend.key.width = unit(legend_width_cm, "cm"))

ds_ecosystems %>%
  filter(is.na(evenness_pielou) != TRUE) %>%
  ggplot(aes(x = evenness_pielou,
             y = bioarea_mm2_per_ml)) +
  geom_point() +
  labs(x = axis_names$axis_name[axis_names$variable == "evenness_pielou"],
       y = axis_names$axis_name[axis_names$variable == "bioarea_mm2_per_ml"]) + 
  theme_bw() +
    theme(panel.grid.major = element_blank(),
          panel.grid.minor = element_blank(),
          legend.position = legend_position,
          legend.key.width = unit(legend_width_cm, "cm"))

Evaporation (both disturbance levels)

response_variable_selected = "water_addition_ml"

UNLIKE ALL THE OTHER ANALYSIS, THIS INCLUDES BOTH DISTURBANCE LEVELS.

We want to know whether the size of an ecosystem influenced its evaporation rate. We first start from plotting how the water that was added to the cultures changed across size through its mean ± 95 confidence interval:

# --- FILTER DATASET --- #

ds_ecosystems_both_disturbances_filtered = ds_ecosystems_both_disturbances %>%
  filter(!is.na(water_addition_ml)) %>%
  mutate(sqrt_water_addition_ml = sqrt(water_addition_ml),
         log_water_addition_ml = log(water_addition_ml),
         inv_water_addition_ml = 1 / water_addition_ml)
# --- PLOT WATER ADDITION MEAN ± 95 CI --- #

ds_ecosystems_both_disturbances_filtered %>%
  summarySE(measurevar = response_variable_selected,
            groupvars = c("day", "ecosystem_size")) %>%
  ggplot(aes(x = day,
             y = get(response_variable_selected),
             group = interaction(day, ecosystem_size),
             color = ecosystem_size)) +
  geom_point(stat = "summary",
             fun = "mean",
             position = position_dodge(dodging),
             size = treatment_points_size) + 
  geom_line(stat = "summary",
            fun = "mean",
            aes(group = ecosystem_size),
            position = position_dodge(dodging),
            linewidth = treatment_lines_linewidth) +
  geom_errorbar(aes(ymax = get(response_variable_selected) + ci,
                    ymin = get(response_variable_selected) - ci),
                width = width_errorbar,
                position = position_dodge(dodging)) +
  labs(x = "Day",
       y = "Water addition (ml)",
       color = "") +
  scale_x_continuous(breaks = unique(ds_ecosystems$day)) +
  geom_vline(xintercept = resource_flow_days,
             linetype = resource_flow_line_type,
             color = resource_flow_line_colour,
             linewidth = resource_flow_line_width) +
  theme_bw() +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position = legend_position) +
  scale_color_manual(values = c("#000000", "#737373", "#bdbdbd")) +
  geom_rect(xmin = grey_background_xmin, 
              xmax = grey_background_xmax,
              ymin = grey_background_ymin, 
              ymax = grey_background_ymax, 
              fill = grey_background_fill, 
              alpha = grey_background_alpha,
              color = grey_background_color)

Single replicates
# --- PLOT WATER ADDITION SINGLE REPLICATES --- #

ds_ecosystems_both_disturbances_filtered %>%
  ggplot(aes(x = day,
             y = get(response_variable_selected),
             group = interaction(culture_ID, day),
             color = ecosystem_size)) +
  geom_point() + 
  geom_line(aes(group = culture_ID)) +
  scale_x_continuous(breaks = unique(ds_ecosystems$day)) +
    theme_bw() +
    theme(panel.grid.major = element_blank(),
          panel.grid.minor = element_blank(),
          legend.position = legend_position) +
      geom_rect(xmin = grey_background_xmin, 
                xmax = grey_background_xmax,
                ymin = grey_background_ymin, 
                ymax = grey_background_ymax, 
                fill = grey_background_fill, 
                alpha = grey_background_alpha,
                color = grey_background_color) +
  labs(x = "Day",
       y = "Water addition (ml)",
       color = "") +
  scale_color_manual(values = c("#000000", "#737373", "#bdbdbd"))
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_size +
                    (1 | time_point),
                  data = ds_ecosystems_both_disturbances_filtered,
                  REML = FALSE)

null_model = lmer(get(response_variable_selected) ~
                    (1 | time_point),
                  data = ds_ecosystems_both_disturbances_filtered,
                  REML = FALSE)


Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  print()
##    deltaAIC    p_value R2
## 1 -4.690089 0.01297093 NA
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_size + (1 | time_point)
##    Data: ds_ecosystems_both_disturbances_filtered
## 
##      AIC      BIC   logLik deviance df.resid 
##    748.4    769.9   -369.2    738.4      538 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -3.8   -0.7    0.1    0.4    4.5 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev.
##  time_point (Intercept) 0.2      0.4     
##  Residual               0.2      0.5     
## Number of obs: 543, groups:  time_point, 5
## 
## Fixed effects:
##                      Estimate Std. Error     df t value Pr(>|t|)    
## (Intercept)              1.63       0.20   5.18       8    4e-04 ***
## ecosystem_sizeMedium    -0.13       0.05 538.00      -3    0.009 ** 
## ecosystem_sizeSmall     -0.12       0.05 538.00      -2    0.015 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecsy_M
## ecsystm_szM -0.109       
## ecsystm_szS -0.117  0.459
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(ds_ecosystems_both_disturbances_filtered, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))

Shannon

response_variable_selected = "shannon"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT MEAN ± 95% CI --- #

"High disturbance"
## [1] "High disturbance"
plot.all.patches.points(data = ds_ecosystems_both_disturbances %>% filter(disturbance == "high"),
                        response_variable_selected)
## Warning in qt(conf.interval/2 + 0.5, datac$N - 1): NaNs produced

"Low disturbance"
## [1] "Low disturbance"
plot.all.patches.points(data = ds_ecosystems_both_disturbances %>% filter(disturbance == "low"),
                        response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. To do so, we go through the following steps.

  1. Add baseline level of this response variable (time point 1) to the cultures.
  2. Filter the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, the time points preceding the initial disturbance and resource flow, and the last time point which we are not including because we do not know how much water evaporated previously from the water addition.
  3. Plot the data to make sure that what filtered in the right way.
  4. Develop mixed effect models to examine how ecosystem type influenced this variable.
# --- ADD BASELINES --- #

baselines = ds_ecosystems_both_disturbances %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

data_for_analysis = ds_ecosystems_both_disturbances %>%
  left_join(baselines)
# --- FILTER DATA AND CHANGE THE NAME OF LEVELS --- #

data_for_analysis = data_for_analysis %>%
  filter(time_point %in% time_points_model,
         !is.na(!!sym(response_variable_selected)),
         !is.na(water_addition_ml)) %>%
  mutate(ecosystem_type = case_when(ecosystem_type == "Small unconnected" ~ "S",
                                    ecosystem_type == "Medium unconnected" ~ "M",
                                    ecosystem_type == "Large unconnected" ~ "L",
                                    ecosystem_type == "Small connected to small" ~ "S_S",
                                    ecosystem_type == "Small connected to large" ~ "S_L",
                                    ecosystem_type == "Medium connected to medium" ~ "M_M",
                                    ecosystem_type == "Large connected to large" ~ "L_L",
                                    ecosystem_type == "Large connected to small" ~ "L_S",
                                    TRUE ~ ecosystem_type))
# --- ADD EVAPORATION RATES RESIDUALS --- #

evaporation_model = lm(get(response_variable_selected) ~
                    ecosystem_type * disturbance * day + 
                    baseline * day,
                  data = data_for_analysis) 

par(mfrow = c(2, 2))
plot(evaporation_model)

data_for_analysis = data_for_analysis %>%
  mutate(evaporation_residuals = residuals(evaporation_model))
# --- PLOT MEAN ± 95% CI OF FILTERED DATA --- #

"High disturbance"
## [1] "High disturbance"
plot.all.patches.points(data = data_for_analysis %>% filter(disturbance == "high"),
                        response_variable_selected)

"Low disturbance"
## [1] "Low disturbance"
plot.all.patches.points(data = data_for_analysis %>% filter(disturbance == "low"),
                        response_variable_selected)

# --- CHECK COLLINEARITY --- #

# # Select the relevant numeric columns (ensure that they are numeric)
# numeric_data <- data_for_analysis %>% 
#   select(day, water_addition_ml, baseline)
# 
# # Calculate the correlation matrix
# cor_matrix <- cor(numeric_data, use = "complete.obs")
# 
# # Use corrplot to visualize the correlation matrix
# corrplot::corrplot(cor_matrix, method = 'number')
# --- CONSTRUCT MODEL --- #

# full_model = lmer(get(response_variable_selected) ~
#                     ecosystem_type * disturbance * day + 
#                     water_addition_ml * day +
#                     baseline * day +
#                     (day | culture_ID),
#                   data = data_for_analysis,
#                   REML = FALSE)

full_model <- glmmTMB(get(response_variable_selected) ~
                        ecosystem_type * disturbance * scale(day) +
                        scale(water_addition_ml) * scale(day) +
                        scale(baseline) * scale(day) +
                        (day | culture_ID),
                      data = data_for_analysis,
                      family = tweedie(link = "log"),
                      control = glmmTMBControl(optimizer = "optim"))
## Warning in finalizeTMB(TMBStruc, obj, fit, h, data.tmb.old): Model convergence
## problem; non-positive-definite Hessian matrix. See vignette('troubleshooting')
## Warning in finalizeTMB(TMBStruc, obj, fit, h, data.tmb.old): Model convergence
## problem; . See vignette('troubleshooting'), help('diagnose')
# --- SHOW MODEL SUMMARY --- #

print(summary(full_model), digits = 1)
## Warning in sqrt(diag(vcovs)): NaNs produced
##  Family: tweedie  ( log )
## Formula:          
## get(response_variable_selected) ~ ecosystem_type * disturbance *  
##     scale(day) + scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
## Data: data_for_analysis
## 
##      AIC      BIC   logLik deviance df.resid 
##       NA       NA       NA       NA      489 
## 
## Random effects:
## 
## Conditional model:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 0.7      0.8           
##             day         0.7      0.9      0.17 
## Number of obs: 530, groups:  culture_ID, 109
## 
## Dispersion parameter for tweedie family (): 0.459 
## 
## Conditional model:
##                                             Estimate Std. Error z value
## (Intercept)                                    0.049      7.726     0.0
## ecosystem_typeL_L                              0.070      9.375     0.0
## ecosystem_typeL_S                              0.008     10.807     0.0
## ecosystem_typeM                                0.020     10.890     0.0
## ecosystem_typeM_M                              0.065      9.342     0.0
## ecosystem_typeS                                0.066        NaN     NaN
## ecosystem_typeS_L                              0.069      6.705     0.0
## ecosystem_typeS_S                              0.064        NaN     NaN
## disturbancelow                                 0.071     10.658     0.0
## scale(day)                                    -0.010      2.172     0.0
## scale(water_addition_ml)                       0.056      0.051     1.1
## scale(baseline)                                0.054      1.381     0.0
## ecosystem_typeL_L:disturbancelow               0.061     13.222     0.0
## ecosystem_typeL_S:disturbancelow               0.138     15.089     0.0
## ecosystem_typeM:disturbancelow                -0.026     14.632     0.0
## ecosystem_typeM_M:disturbancelow               0.024     12.999     0.0
## ecosystem_typeS:disturbancelow                 0.049      1.436     0.0
## ecosystem_typeS_L:disturbancelow              -0.105     11.318     0.0
## ecosystem_typeS_S:disturbancelow               0.056     10.417     0.0
## ecosystem_typeL_L:scale(day)                   0.035      2.636     0.0
## ecosystem_typeL_S:scale(day)                  -0.022      3.039     0.0
## ecosystem_typeM:scale(day)                    -0.039      3.062     0.0
## ecosystem_typeM_M:scale(day)                   0.039      2.627     0.0
## ecosystem_typeS:scale(day)                     0.070        NaN     NaN
## ecosystem_typeS_L:scale(day)                   0.040      1.868     0.0
## ecosystem_typeS_S:scale(day)                  -0.055        NaN     NaN
## disturbancelow:scale(day)                     -0.013      2.996     0.0
## scale(day):scale(water_addition_ml)            0.020      0.047     0.4
## scale(day):scale(baseline)                     0.059      0.386     0.2
## ecosystem_typeL_L:disturbancelow:scale(day)    0.074      3.718     0.0
## ecosystem_typeL_S:disturbancelow:scale(day)   -0.008      4.241     0.0
## ecosystem_typeM:disturbancelow:scale(day)      0.031      4.111     0.0
## ecosystem_typeM_M:disturbancelow:scale(day)    0.031      3.654     0.0
## ecosystem_typeS:disturbancelow:scale(day)      0.044      0.774     0.1
## ecosystem_typeS_L:disturbancelow:scale(day)   -0.059      3.167     0.0
## ecosystem_typeS_S:disturbancelow:scale(day)    0.064      2.922     0.0
##                                             Pr(>|z|)
## (Intercept)                                      1.0
## ecosystem_typeL_L                                1.0
## ecosystem_typeL_S                                1.0
## ecosystem_typeM                                  1.0
## ecosystem_typeM_M                                1.0
## ecosystem_typeS                                  NaN
## ecosystem_typeS_L                                1.0
## ecosystem_typeS_S                                NaN
## disturbancelow                                   1.0
## scale(day)                                       1.0
## scale(water_addition_ml)                         0.3
## scale(baseline)                                  1.0
## ecosystem_typeL_L:disturbancelow                 1.0
## ecosystem_typeL_S:disturbancelow                 1.0
## ecosystem_typeM:disturbancelow                   1.0
## ecosystem_typeM_M:disturbancelow                 1.0
## ecosystem_typeS:disturbancelow                   1.0
## ecosystem_typeS_L:disturbancelow                 1.0
## ecosystem_typeS_S:disturbancelow                 1.0
## ecosystem_typeL_L:scale(day)                     1.0
## ecosystem_typeL_S:scale(day)                     1.0
## ecosystem_typeM:scale(day)                       1.0
## ecosystem_typeM_M:scale(day)                     1.0
## ecosystem_typeS:scale(day)                       NaN
## ecosystem_typeS_L:scale(day)                     1.0
## ecosystem_typeS_S:scale(day)                     NaN
## disturbancelow:scale(day)                        1.0
## scale(day):scale(water_addition_ml)              0.7
## scale(day):scale(baseline)                       0.9
## ecosystem_typeL_L:disturbancelow:scale(day)      1.0
## ecosystem_typeL_S:disturbancelow:scale(day)      1.0
## ecosystem_typeM:disturbancelow:scale(day)        1.0
## ecosystem_typeM_M:disturbancelow:scale(day)      1.0
## ecosystem_typeS:disturbancelow:scale(day)        1.0
## ecosystem_typeS_L:disturbancelow:scale(day)      1.0
## ecosystem_typeS_S:disturbancelow:scale(day)      1.0
# --- RUN ANOVA --- #

car::Anova(full_model, type = "III")
## Analysis of Deviance Table (Type III Wald chisquare tests)
## 
## Response: get(response_variable_selected)
##                                        Chisq Df Pr(>Chisq)
## (Intercept)                           0.0000  1     0.9949
## ecosystem_type                        0.0001  7     1.0000
## disturbance                           0.0000  1     0.9947
## scale(day)                            0.0000  1     0.9962
## scale(water_addition_ml)              1.2133  1     0.2707
## scale(baseline)                       0.0015  1     0.9688
## ecosystem_type:disturbance            0.0003  7     1.0000
## ecosystem_type:scale(day)             0.0039  7     1.0000
## disturbance:scale(day)                0.0000  1     0.9966
## scale(day):scale(water_addition_ml)   0.1868  1     0.6656
## scale(day):scale(baseline)            0.0231  1     0.8792
## ecosystem_type:disturbance:scale(day) 0.0017  7     1.0000
Model contrast coding
# --- GET ECOSYSTEM TYPE CONSTRASTS --- #

emmeans_output = emmeans(full_model,
        specs = pairwise ~ ecosystem_type * disturbance,
        adjust = "tukey",
        bias.adj = TRUE,
        lmer.df = "satterthwaite") 


emmeans_output
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## Warning in .qf.non0(object@V, x): Negative variance estimate obtained!
## $emmeans
##  ecosystem_type disturbance emmean   SE  df asymp.LCL asymp.UCL
##  L              high        0.0494 7.73 Inf    -15.09     15.19
##  L_L            high        0.1197 5.42 Inf    -10.51     10.75
##  L_S            high        0.0570 7.66 Inf    -14.96     15.07
##  M              high        0.0690 7.66 Inf    -14.94     15.07
##  M_M            high        0.1145 5.48 Inf    -10.62     10.85
##  S              high        0.1157  NaN Inf       NaN       NaN
##  S_L            high        0.1182  NaN Inf       NaN       NaN
##  S_S            high        0.1130  NaN Inf       NaN       NaN
##  L              low         0.1203 7.64 Inf    -14.84     15.08
##  L_L            low         0.2520 5.32 Inf    -10.17     10.67
##  L_S            low         0.2662 7.25 Inf    -13.95     14.48
##  M              low         0.1137 7.20 Inf    -14.01     14.23
##  M_M            low         0.2096 5.48 Inf    -10.54     10.96
##  S              low         0.2361 5.42 Inf    -10.38     10.85
##  S_L            low         0.0839 7.80 Inf    -15.21     15.38
##  S_S            low         0.2395 4.20 Inf     -7.99      8.47
## 
## Results are given on the log (not the response) scale. 
## Confidence level used: 0.95 
## 
## $contrasts
##  contrast             estimate    SE  df z.ratio p.value
##  L high - L_L high   -0.070344  9.38 Inf  -0.008  1.0000
##  L high - L_S high   -0.007617 10.81 Inf  -0.001  1.0000
##  L high - M high     -0.019654 10.89 Inf  -0.002  1.0000
##  L high - M_M high   -0.065118  9.34 Inf  -0.007  1.0000
##  L high - S high     -0.066334   NaN Inf     NaN     NaN
##  L high - S_L high   -0.068784  6.70 Inf  -0.010  1.0000
##  L high - S_S high   -0.063653   NaN Inf     NaN     NaN
##  L high - L low      -0.070903 10.66 Inf  -0.007  1.0000
##  L high - L_L low    -0.202587  9.26 Inf  -0.022  1.0000
##  L high - L_S low    -0.216819 10.78 Inf  -0.020  1.0000
##  L high - M low      -0.064341 10.67 Inf  -0.006  1.0000
##  L high - M_M low    -0.160174  9.38 Inf  -0.017  1.0000
##  L high - S low      -0.186673  9.20 Inf  -0.020  1.0000
##  L high - S_L low    -0.034558 11.15 Inf  -0.003  1.0000
##  L high - S_S low    -0.190097  8.53 Inf  -0.022  1.0000
##  L_L high - L_S high  0.062727  9.30 Inf   0.007  1.0000
##  L_L high - M high    0.050689  9.39 Inf   0.005  1.0000
##  L_L high - M_M high  0.005226  7.67 Inf   0.001  1.0000
##  L_L high - S high    0.004010   NaN Inf     NaN     NaN
##  L_L high - S_L high  0.001559  5.01 Inf   0.000  1.0000
##  L_L high - S_S high  0.006691   NaN Inf     NaN     NaN
##  L_L high - L low    -0.000559  9.34 Inf   0.000  1.0000
##  L_L high - L_L low  -0.132243  7.61 Inf  -0.017  1.0000
##  L_L high - L_S low  -0.146475  9.02 Inf  -0.016  1.0000
##  L_L high - M low     0.006003  8.94 Inf   0.001  1.0000
##  L_L high - M_M low  -0.089830  7.65 Inf  -0.012  1.0000
##  L_L high - S low    -0.116329  7.86 Inf  -0.015  1.0000
##  L_L high - S_L low   0.035785  9.59 Inf   0.004  1.0000
##  L_L high - S_S low  -0.119753  6.94 Inf  -0.017  1.0000
##  L_S high - M high   -0.012038 10.84 Inf  -0.001  1.0000
##  L_S high - M_M high -0.057501  9.26 Inf  -0.006  1.0000
##  L_S high - S high   -0.058717   NaN Inf     NaN     NaN
##  L_S high - S_L high -0.061168  5.71 Inf  -0.011  1.0000
##  L_S high - S_S high -0.056036   NaN Inf     NaN     NaN
##  L_S high - L low    -0.063286 10.51 Inf  -0.006  1.0000
##  L_S high - L_L low  -0.194970  9.12 Inf  -0.021  1.0000
##  L_S high - L_S low  -0.209202 10.89 Inf  -0.019  1.0000
##  L_S high - M low    -0.056724 10.79 Inf  -0.005  1.0000
##  L_S high - M_M low  -0.152557  9.34 Inf  -0.016  1.0000
##  L_S high - S low    -0.179056  8.74 Inf  -0.020  1.0000
##  L_S high - S_L low  -0.026942 11.11 Inf  -0.002  1.0000
##  L_S high - S_S low  -0.182480  8.19 Inf  -0.022  1.0000
##  M high - M_M high   -0.045463  9.43 Inf  -0.005  1.0000
##  M high - S high     -0.046679   NaN Inf     NaN     NaN
##  M high - S_L high   -0.049130  6.98 Inf  -0.007  1.0000
##  M high - S_S high   -0.043998   NaN Inf     NaN     NaN
##  M high - L low      -0.051249 10.83 Inf  -0.005  1.0000
##  M high - L_L low    -0.182933  9.33 Inf  -0.020  1.0000
##  M high - L_S low    -0.197165 10.54 Inf  -0.019  1.0000
##  M high - M low      -0.044687 10.52 Inf  -0.004  1.0000
##  M high - M_M low    -0.140520  9.43 Inf  -0.015  1.0000
##  M high - S low      -0.167018  9.36 Inf  -0.018  1.0000
##  M high - S_L low    -0.014904 10.93 Inf  -0.001  1.0000
##  M high - S_S low    -0.170442  8.73 Inf  -0.020  1.0000
##  M_M high - S high   -0.001216   NaN Inf     NaN     NaN
##  M_M high - S_L high -0.003667  5.38 Inf  -0.001  1.0000
##  M_M high - S_S high  0.001465   NaN Inf     NaN     NaN
##  M_M high - L low    -0.005785  9.33 Inf  -0.001  1.0000
##  M_M high - L_L low  -0.137469  7.63 Inf  -0.018  1.0000
##  M_M high - L_S low  -0.151701  9.05 Inf  -0.017  1.0000
##  M_M high - M low     0.000777  8.93 Inf   0.000  1.0000
##  M_M high - M_M low  -0.095056  7.62 Inf  -0.012  1.0000
##  M_M high - S low    -0.121555  8.01 Inf  -0.015  1.0000
##  M_M high - S_L low   0.030559  9.69 Inf   0.003  1.0000
##  M_M high - S_S low  -0.124979  7.01 Inf  -0.018  1.0000
##  S high - S_L high   -0.002451  4.43 Inf  -0.001  1.0000
##  S high - S_S high    0.002681  3.90 Inf   0.001  1.0000
##  S high - L low      -0.004569   NaN Inf     NaN     NaN
##  S high - L_L low    -0.136253   NaN Inf     NaN     NaN
##  S high - L_S low    -0.150485   NaN Inf     NaN     NaN
##  S high - M low       0.001993   NaN Inf     NaN     NaN
##  S high - M_M low    -0.093840   NaN Inf     NaN     NaN
##  S high - S low      -0.120339   NaN Inf     NaN     NaN
##  S high - S_L low     0.031775   NaN Inf     NaN     NaN
##  S high - S_S low    -0.123763   NaN Inf     NaN     NaN
##  S_L high - S_S high  0.005132  9.33 Inf   0.001  1.0000
##  S_L high - L low    -0.002119  8.73 Inf   0.000  1.0000
##  S_L high - L_L low  -0.133802  6.22 Inf  -0.022  1.0000
##  S_L high - L_S low  -0.148035   NaN Inf     NaN     NaN
##  S_L high - M low     0.004444   NaN Inf     NaN     NaN
##  S_L high - M_M low  -0.091390  4.17 Inf  -0.022  1.0000
##  S_L high - S low    -0.117888 10.46 Inf  -0.011  1.0000
##  S_L high - S_L low   0.034226  6.83 Inf   0.005  1.0000
##  S_L high - S_S low  -0.121312  8.18 Inf  -0.015  1.0000
##  S_S high - L low    -0.007250  4.54 Inf  -0.002  1.0000
##  S_S high - L_L low  -0.138934   NaN Inf     NaN     NaN
##  S_S high - L_S low  -0.153166   NaN Inf     NaN     NaN
##  S_S high - M low    -0.000688   NaN Inf     NaN     NaN
##  S_S high - M_M low  -0.096521   NaN Inf     NaN     NaN
##  S_S high - S low    -0.123020  8.33 Inf  -0.015  1.0000
##  S_S high - S_L low   0.029095   NaN Inf     NaN     NaN
##  S_S high - S_S low  -0.126444  4.40 Inf  -0.029  1.0000
##  L low - L_L low     -0.131684  9.41 Inf  -0.014  1.0000
##  L low - L_S low     -0.145916 10.26 Inf  -0.014  1.0000
##  L low - M low        0.006562 10.12 Inf   0.001  1.0000
##  L low - M_M low     -0.089271  9.21 Inf  -0.010  1.0000
##  L low - S low       -0.115770 10.22 Inf  -0.011  1.0000
##  L low - S_L low      0.036345 11.11 Inf   0.003  1.0000
##  L low - S_S low     -0.119194  9.19 Inf  -0.013  1.0000
##  L_L low - L_S low   -0.014232  8.70 Inf  -0.002  1.0000
##  L_L low - M low      0.138246  8.62 Inf   0.016  1.0000
##  L_L low - M_M low    0.042413  7.53 Inf   0.006  1.0000
##  L_L low - S low      0.015914  8.38 Inf   0.002  1.0000
##  L_L low - S_L low    0.168029  9.52 Inf   0.018  1.0000
##  L_L low - S_S low    0.012490  7.29 Inf   0.002  1.0000
##  L_S low - M low      0.152478 10.85 Inf   0.014  1.0000
##  L_S low - M_M low    0.056645  9.25 Inf   0.006  1.0000
##  L_S low - S low      0.030146  7.35 Inf   0.004  1.0000
##  L_S low - S_L low    0.182261 10.58 Inf   0.017  1.0000
##  L_S low - S_S low    0.026722  7.31 Inf   0.004  1.0000
##  M low - M_M low     -0.095833  9.14 Inf  -0.010  1.0000
##  M low - S low       -0.122332  7.29 Inf  -0.017  1.0000
##  M low - S_L low      0.029783 10.65 Inf   0.003  1.0000
##  M low - S_S low     -0.125756  7.18 Inf  -0.018  1.0000
##  M_M low - S low     -0.026499  7.53 Inf  -0.004  1.0000
##  M_M low - S_L low    0.125616  9.69 Inf   0.013  1.0000
##  M_M low - S_S low   -0.029923  6.67 Inf  -0.004  1.0000
##  S low - S_L low      0.152114  9.39 Inf   0.016  1.0000
##  S low - S_S low     -0.003424  9.21 Inf   0.000  1.0000
##  S_L low - S_S low   -0.155538  8.92 Inf  -0.017  1.0000
## 
## Results are given on the log (not the response) scale. 
## P value adjustment: tukey method for comparing a family of 14.2931142241337 estimates
high_L = c(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
high_L_L = c(0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
high_L_S = c(0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
high_M = c(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
high_M_M = c(0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
high_S = c(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
high_S_L = c(0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0)
high_S_S = c(0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0)
low_L = c(rep(0,8), 1, rep(0,7))
low_L_L = c(rep(0,9), 1, rep(0,6))
low_L_S = c(rep(0,10), 1, rep(0,5))
low_M = c(rep(0,11), 1, rep(0,4))
low_M_M = c(rep(0,12), 1, rep(0,3))
low_S = c(rep(0,13), 1, rep(0,2))
low_S_L = c(rep(0,14), 1, rep(0,1))
low_S_S = c(rep(0,15), 1)

n_of_digits = 3
contrasts = contrast(emmeans_output, 
                     method = list("high S_L - S" = high_S_L - high_S,
                                   "high S_L - S_S" = high_S_L - high_S_S,
                                   "high S_S - S" = high_S_S - high_S,
                                   "high M_M - M" = high_M_M - high_M,
                                   "high L_S - L" = high_L_S - high_L,
                                   "high L_S - L_L" = high_L_S - high_L_L,
                                   "high L_L - L" = high_L_L - high_L,
                                   "low S_L - S" = low_S_L - low_S,
                                   "low S_L - S_S" = low_S_L - low_S_S,
                                   "low S_S - S" = low_S_S - low_S,
                                   "low M_M - M" = low_M_M - low_M,
                                   "low L_S - L" = low_L_S - low_L,
                                   "low L_S - L_L" = low_L_S - low_L_L,
                                   "low L_L - L" = low_L_L - low_L)) %>%
  as.data.frame() %>%
  mutate(p.value = round(p.value, digits = n_of_digits),
         estimate = round(estimate, digits = n_of_digits),
         SE = round(SE, digits = n_of_digits),
         df = round(df, digits = n_of_digits),
         z.ratio = round(z.ratio, digits = n_of_digits),
         e = "",
         e = ifelse(p.value > 0.1, 
                           "",
                           e),
         e = ifelse(p.value < 0.05, 
                           "*",
                           e),
         e = ifelse(p.value < 0.01, 
                           "**",
                           e),
         e = ifelse(p.value < 0.001, 
                           "***",
                           e)) %>%
  rename(" " = e)
# --- SHOW ECOSYSTEM TYPE CONSTRASTS --- #
contrasts
##          contrast estimate     SE  df z.ratio p.value  
## 1    high S_L - S    0.002  4.430 Inf   0.001   1.000  
## 2  high S_L - S_S    0.005  9.331 Inf   0.001   1.000  
## 3    high S_S - S   -0.003  3.899 Inf  -0.001   0.999  
## 4    high M_M - M    0.045  9.425 Inf   0.005   0.996  
## 5    high L_S - L    0.008 10.807 Inf   0.001   0.999  
## 6  high L_S - L_L   -0.063  9.298 Inf  -0.007   0.995  
## 7    high L_L - L    0.070  9.375 Inf   0.008   0.994  
## 8     low S_L - S   -0.152  9.389 Inf  -0.016   0.987  
## 9   low S_L - S_S   -0.156  8.917 Inf  -0.017   0.986  
## 10    low S_S - S    0.003  9.214 Inf   0.000   1.000  
## 11    low M_M - M    0.096  9.139 Inf   0.010   0.992  
## 12    low L_S - L    0.146 10.257 Inf   0.014   0.989  
## 13  low L_S - L_L    0.014  8.703 Inf   0.002   0.999  
## 14    low L_L - L    0.132  9.413 Inf   0.014   0.989


# --- CONSTRUCT RESIDUALS VS FITTED VALUES PLOT --- #

res_vs_fit = data_for_analysis %>%
    mutate(predicted = fitted(full_model),
           residuals = resid(full_model)) %>%
    plot_ly(x = ~predicted,
            y = ~residuals,
            type = "scatter",
            mode = "markers",
            marker = list(size = 5, color = "#4C78A8"),
            text = paste(" ID: ", 
                         data_for_analysis$culture_ID, 
                         "<br>",
                         "Day: ", 
                         data_for_analysis$day, 
                         "<br>",
                         "Patch Type: ", 
                         data_for_analysis$ecosystem_type, 
                         "<br>",
                         "Biomass density: ", 
                         round(data_for_analysis$bioarea_mm2_per_ml, digits = 2), 
                         "<br>",
                         "Species richness: ", 
                         data_for_analysis$species_richness, 
                         "<br>"),
            hoverinfo = "text") %>%
    plotly::layout(title = "Residuals vs. Fitted Values",
                   xaxis = list(title = "Fitted Values"),
                   yaxis = list(title = "Residuals"))
# --- PLOT RESIDUALS --- #

qqnorm(resid(full_model))
qqline(resid(full_model))

res_vs_fit

Biomass

response_variable_selected = "bioarea_mm2_per_ml"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT MEAN ± 95% CI --- #

"High disturbance"
## [1] "High disturbance"
plot.all.patches.points(data = ds_ecosystems_both_disturbances %>% filter(disturbance == "high"),
                        response_variable_selected)

"Low disturbance"
## [1] "Low disturbance"
plot.all.patches.points(data = ds_ecosystems_both_disturbances %>% filter(disturbance == "low"),
                        response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. To do so, we go through the following steps.

  1. Add baseline level of this response variable (time point 1) to the cultures.
  2. Filter the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, the time points preceding the initial disturbance and resource flow, and the last time point which we are not including because we do not know how much water evaporated previously from the water addition.
  3. Plot the data to make sure that what filtered in the right way.
  4. Develop mixed effect models to examine how ecosystem type influenced this variable.
# --- ADD BASELINES --- #

baselines = ds_ecosystems_both_disturbances %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

data_for_analysis = ds_ecosystems_both_disturbances %>%
  left_join(baselines)
# --- FILTER DATA AND CHANGE THE NAME OF LEVELS --- #

data_for_analysis = data_for_analysis %>%
  filter(time_point %in% time_points_model,
         !is.na(!!sym(response_variable_selected)),
         !is.na(water_addition_ml)) %>%
  mutate(ecosystem_type = case_when(ecosystem_type == "Small unconnected" ~ "S",
                                    ecosystem_type == "Medium unconnected" ~ "M",
                                    ecosystem_type == "Large unconnected" ~ "L",
                                    ecosystem_type == "Small connected to small" ~ "S_S",
                                    ecosystem_type == "Small connected to large" ~ "S_L",
                                    ecosystem_type == "Medium connected to medium" ~ "M_M",
                                    ecosystem_type == "Large connected to large" ~ "L_L",
                                    ecosystem_type == "Large connected to small" ~ "L_S",
                                    TRUE ~ ecosystem_type))
# --- ADD EVAPORATION RATES RESIDUALS --- #

evaporation_model = lm(get(response_variable_selected) ~
                    ecosystem_type * disturbance * day + 
                    baseline * day,
                  data = data_for_analysis) 

par(mfrow = c(2, 2))
plot(evaporation_model)

data_for_analysis = data_for_analysis %>%
  mutate(evaporation_residuals = residuals(evaporation_model))
# --- PLOT MEAN ± 95% CI OF FILTERED DATA --- #

"High disturbance"
## [1] "High disturbance"
plot.all.patches.points(data = data_for_analysis %>% filter(disturbance == "high"),
                        response_variable_selected)

"Low disturbance"
## [1] "Low disturbance"
plot.all.patches.points(data = data_for_analysis %>% filter(disturbance == "low"),
                        response_variable_selected)

# --- CHECK COLLINEARITY --- #

# # Select the relevant numeric columns (ensure that they are numeric)
# numeric_data <- data_for_analysis %>% 
#   select(day, water_addition_ml, baseline)
# 
# # Calculate the correlation matrix
# cor_matrix <- cor(numeric_data, use = "complete.obs")
# 
# # Use corrplot to visualize the correlation matrix
# corrplot::corrplot(cor_matrix, method = 'number')
# --- CONSTRUCT MODEL --- #

# full_model = lmer(get(response_variable_selected) ~
#                     ecosystem_type * disturbance * day + 
#                     water_addition_ml * day +
#                     baseline * day +
#                     (day | culture_ID),
#                   data = data_for_analysis,
#                   REML = FALSE)

full_model <- glmmTMB(get(response_variable_selected) ~
                        ecosystem_type * disturbance * scale(day) +
                        scale(water_addition_ml) * scale(day) +
                        scale(baseline) * scale(day) +
                        (day | culture_ID),
                      data = data_for_analysis,
                      family = tweedie(link = "log"),
                      control = glmmTMBControl(optimizer = "optim"))
## Warning in finalizeTMB(TMBStruc, obj, fit, h, data.tmb.old): Model convergence
## problem; non-positive-definite Hessian matrix. See vignette('troubleshooting')
## Warning in finalizeTMB(TMBStruc, obj, fit, h, data.tmb.old): Model convergence
## problem; . See vignette('troubleshooting'), help('diagnose')
# --- SHOW MODEL SUMMARY --- #

print(summary(full_model), digits = 1)
##  Family: tweedie  ( log )
## Formula:          
## get(response_variable_selected) ~ ecosystem_type * disturbance *  
##     scale(day) + scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
## Data: data_for_analysis
## 
##      AIC      BIC   logLik deviance df.resid 
##       NA       NA       NA       NA      502 
## 
## Random effects:
## 
## Conditional model:
##  Groups     Name        Variance Std.Dev. Corr  
##  culture_ID (Intercept) 1.0      1.0            
##             day         0.7      0.9      -0.05 
## Number of obs: 543, groups:  culture_ID, 109
## 
## Dispersion parameter for tweedie family (): 0.792 
## 
## Conditional model:
##                                             Estimate Std. Error z value
## (Intercept)                                    0.082      8.012     0.0
## ecosystem_typeL_L                              0.041      9.546     0.0
## ecosystem_typeL_S                              0.117     10.968     0.0
## ecosystem_typeM                                0.045     11.176     0.0
## ecosystem_typeM_M                              0.045      9.570     0.0
## ecosystem_typeS                                0.222     18.632     0.0
## ecosystem_typeS_L                              0.039     12.924     0.0
## ecosystem_typeS_S                              0.033     13.141     0.0
## disturbancelow                                 0.122     11.559     0.0
## scale(day)                                    -0.529      2.275    -0.2
## scale(water_addition_ml)                       0.073      0.067     1.1
## scale(baseline)                               -0.014      1.822     0.0
## ecosystem_typeL_L:disturbancelow               0.048     13.517     0.0
## ecosystem_typeL_S:disturbancelow               0.062     15.452     0.0
## ecosystem_typeM:disturbancelow                -0.026     15.808     0.0
## ecosystem_typeM_M:disturbancelow               0.034     13.507     0.0
## ecosystem_typeS:disturbancelow                 0.021     16.115     0.0
## ecosystem_typeS_L:disturbancelow              -0.062     15.339     0.0
## ecosystem_typeS_S:disturbancelow               0.042     13.497     0.0
## ecosystem_typeL_L:scale(day)                   0.057      2.712     0.0
## ecosystem_typeL_S:scale(day)                  -0.006      3.116     0.0
## ecosystem_typeM:scale(day)                     0.033      3.176     0.0
## ecosystem_typeM_M:scale(day)                  -0.022      2.719     0.0
## ecosystem_typeS:scale(day)                     0.168      5.306     0.0
## ecosystem_typeS_L:scale(day)                   0.185      3.674     0.1
## ecosystem_typeS_S:scale(day)                   0.004      3.734     0.0
## disturbancelow:scale(day)                     -0.104      3.290     0.0
## scale(day):scale(water_addition_ml)           -0.045      0.059    -0.8
## scale(day):scale(baseline)                     0.025      0.518     0.0
## ecosystem_typeL_L:disturbancelow:scale(day)   -0.128      3.841     0.0
## ecosystem_typeL_S:disturbancelow:scale(day)   -0.053      4.391     0.0
## ecosystem_typeM:disturbancelow:scale(day)     -0.062      4.493     0.0
## ecosystem_typeM_M:disturbancelow:scale(day)    0.008      3.839     0.0
## ecosystem_typeS:disturbancelow:scale(day)      0.041      4.592     0.0
## ecosystem_typeS_L:disturbancelow:scale(day)   -0.042      4.361     0.0
## ecosystem_typeS_S:disturbancelow:scale(day)    0.029      3.839     0.0
##                                             Pr(>|z|)
## (Intercept)                                      1.0
## ecosystem_typeL_L                                1.0
## ecosystem_typeL_S                                1.0
## ecosystem_typeM                                  1.0
## ecosystem_typeM_M                                1.0
## ecosystem_typeS                                  1.0
## ecosystem_typeS_L                                1.0
## ecosystem_typeS_S                                1.0
## disturbancelow                                   1.0
## scale(day)                                       0.8
## scale(water_addition_ml)                         0.3
## scale(baseline)                                  1.0
## ecosystem_typeL_L:disturbancelow                 1.0
## ecosystem_typeL_S:disturbancelow                 1.0
## ecosystem_typeM:disturbancelow                   1.0
## ecosystem_typeM_M:disturbancelow                 1.0
## ecosystem_typeS:disturbancelow                   1.0
## ecosystem_typeS_L:disturbancelow                 1.0
## ecosystem_typeS_S:disturbancelow                 1.0
## ecosystem_typeL_L:scale(day)                     1.0
## ecosystem_typeL_S:scale(day)                     1.0
## ecosystem_typeM:scale(day)                       1.0
## ecosystem_typeM_M:scale(day)                     1.0
## ecosystem_typeS:scale(day)                       1.0
## ecosystem_typeS_L:scale(day)                     1.0
## ecosystem_typeS_S:scale(day)                     1.0
## disturbancelow:scale(day)                        1.0
## scale(day):scale(water_addition_ml)              0.4
## scale(day):scale(baseline)                       1.0
## ecosystem_typeL_L:disturbancelow:scale(day)      1.0
## ecosystem_typeL_S:disturbancelow:scale(day)      1.0
## ecosystem_typeM:disturbancelow:scale(day)        1.0
## ecosystem_typeM_M:disturbancelow:scale(day)      1.0
## ecosystem_typeS:disturbancelow:scale(day)        1.0
## ecosystem_typeS_L:disturbancelow:scale(day)      1.0
## ecosystem_typeS_S:disturbancelow:scale(day)      1.0
# --- RUN ANOVA --- #

car::Anova(full_model, type = "III")
## Analysis of Deviance Table (Type III Wald chisquare tests)
## 
## Response: get(response_variable_selected)
##                                        Chisq Df Pr(>Chisq)
## (Intercept)                           0.0001  1     0.9919
## ecosystem_type                        0.0004  7     1.0000
## disturbance                           0.0001  1     0.9916
## scale(day)                            0.0541  1     0.8161
## scale(water_addition_ml)              1.2106  1     0.2712
## scale(baseline)                       0.0001  1     0.9940
## ecosystem_type:disturbance            0.0001  7     1.0000
## ecosystem_type:scale(day)             0.0081  7     1.0000
## disturbance:scale(day)                0.0010  1     0.9747
## scale(day):scale(water_addition_ml)   0.5918  1     0.4417
## scale(day):scale(baseline)            0.0023  1     0.9617
## ecosystem_type:disturbance:scale(day) 0.0038  7     1.0000
Model contrast coding
# --- GET ECOSYSTEM TYPE CONSTRASTS --- #

emmeans_output = emmeans(full_model,
        specs = pairwise ~ ecosystem_type * disturbance,
        adjust = "tukey",
        bias.adj = TRUE,
        lmer.df = "satterthwaite") 


emmeans_output
## $emmeans
##  ecosystem_type disturbance emmean    SE  df asymp.LCL asymp.UCL
##  L              high        0.0816  8.01 Inf     -15.6      15.8
##  L_L            high        0.1229  5.79 Inf     -11.2      11.5
##  L_S            high        0.1982  7.78 Inf     -15.0      15.4
##  M              high        0.1263  7.80 Inf     -15.2      15.4
##  M_M            high        0.1270  5.49 Inf     -10.6      10.9
##  S              high        0.3036 15.11 Inf     -29.3      29.9
##  S_L            high        0.1210  9.07 Inf     -17.7      17.9
##  S_S            high        0.1144  8.82 Inf     -17.2      17.4
##  L              low         0.2038  9.87 Inf     -19.1      19.6
##  L_L            low         0.2927  7.77 Inf     -14.9      15.5
##  L_S            low         0.3821  8.80 Inf     -16.9      17.6
##  M              low         0.2222  8.34 Inf     -16.1      16.6
##  M_M            low         0.2836  6.23 Inf     -11.9      12.5
##  S              low         0.4465  9.33 Inf     -17.8      18.7
##  S_L            low         0.1811  7.76 Inf     -15.0      15.4
##  S_S            low         0.2787  6.42 Inf     -12.3      12.9
## 
## Results are given on the log (not the response) scale. 
## Confidence level used: 0.95 
## 
## $contrasts
##  contrast             estimate    SE  df z.ratio p.value
##  L high - L_L high   -0.041320  9.55 Inf  -0.004  1.0000
##  L high - L_S high   -0.116634 10.97 Inf  -0.011  1.0000
##  L high - M high     -0.044711 11.18 Inf  -0.004  1.0000
##  L high - M_M high   -0.045352  9.57 Inf  -0.005  1.0000
##  L high - S high     -0.221965 18.63 Inf  -0.012  1.0000
##  L high - S_L high   -0.039397 12.92 Inf  -0.003  1.0000
##  L high - S_S high   -0.032794 13.14 Inf  -0.002  1.0000
##  L high - L low      -0.122230 11.56 Inf  -0.011  1.0000
##  L high - L_L low    -0.211054  9.88 Inf  -0.021  1.0000
##  L high - L_S low    -0.300509 10.99 Inf  -0.027  1.0000
##  L high - M low      -0.140576 10.83 Inf  -0.013  1.0000
##  L high - M_M low    -0.201956  9.43 Inf  -0.021  1.0000
##  L high - S low      -0.364936 13.24 Inf  -0.028  1.0000
##  L high - S_L low    -0.099516 11.17 Inf  -0.009  1.0000
##  L high - S_S low    -0.197048 10.89 Inf  -0.018  1.0000
##  L_L high - L_S high -0.075314  9.56 Inf  -0.008  1.0000
##  L_L high - M high   -0.003391  9.56 Inf   0.000  1.0000
##  L_L high - M_M high -0.004032  7.89 Inf  -0.001  1.0000
##  L_L high - S high   -0.180645 17.48 Inf  -0.010  1.0000
##  L_L high - S_L high  0.001924 11.54 Inf   0.000  1.0000
##  L_L high - S_S high  0.008526 11.64 Inf   0.001  1.0000
##  L_L high - L low    -0.080910 10.33 Inf  -0.008  1.0000
##  L_L high - L_L low  -0.169733  8.52 Inf  -0.020  1.0000
##  L_L high - L_S low  -0.259189  9.73 Inf  -0.027  1.0000
##  L_L high - M low    -0.099256  9.62 Inf  -0.010  1.0000
##  L_L high - M_M low  -0.160636  7.92 Inf  -0.020  1.0000
##  L_L high - S low    -0.323616 11.72 Inf  -0.028  1.0000
##  L_L high - S_L low  -0.058196  9.58 Inf  -0.006  1.0000
##  L_L high - S_S low  -0.155728  9.38 Inf  -0.017  1.0000
##  L_S high - M high    0.071923 11.03 Inf   0.007  1.0000
##  L_S high - M_M high  0.071282  9.45 Inf   0.008  1.0000
##  L_S high - S high   -0.105330 17.64 Inf  -0.006  1.0000
##  L_S high - S_L high  0.077238 12.29 Inf   0.006  1.0000
##  L_S high - S_S high  0.083840 12.29 Inf   0.007  1.0000
##  L_S high - L low    -0.005596 12.13 Inf   0.000  1.0000
##  L_S high - L_L low  -0.094419 10.51 Inf  -0.009  1.0000
##  L_S high - L_S low  -0.183875 11.39 Inf  -0.016  1.0000
##  L_S high - M low    -0.023942 11.11 Inf  -0.002  1.0000
##  L_S high - M_M low  -0.085322  9.66 Inf  -0.009  1.0000
##  L_S high - S low    -0.248302 12.56 Inf  -0.020  1.0000
##  L_S high - S_L low   0.017118 11.01 Inf   0.002  1.0000
##  L_S high - S_S low  -0.080414 10.33 Inf  -0.008  1.0000
##  M high - M_M high   -0.000641  9.56 Inf   0.000  1.0000
##  M high - S high     -0.177254 17.20 Inf  -0.010  1.0000
##  M high - S_L high    0.005314 12.10 Inf   0.000  1.0000
##  M high - S_S high    0.011917 11.92 Inf   0.001  1.0000
##  M high - L low      -0.077519 12.35 Inf  -0.006  1.0000
##  M high - L_L low    -0.166343 10.84 Inf  -0.015  1.0000
##  M high - L_S low    -0.255798 11.64 Inf  -0.022  1.0000
##  M high - M low      -0.095865 11.42 Inf  -0.008  1.0000
##  M high - M_M low    -0.157245  9.96 Inf  -0.016  1.0000
##  M high - S low      -0.320225 12.19 Inf  -0.026  1.0000
##  M high - S_L low    -0.054805 10.91 Inf  -0.005  1.0000
##  M high - S_S low    -0.152337 10.30 Inf  -0.015  1.0000
##  M_M high - S high   -0.176613 16.56 Inf  -0.011  1.0000
##  M_M high - S_L high  0.005955 10.88 Inf   0.001  1.0000
##  M_M high - S_S high  0.012558 10.81 Inf   0.001  1.0000
##  M_M high - L low    -0.076878 10.94 Inf  -0.007  1.0000
##  M_M high - L_L low  -0.165702  9.09 Inf  -0.018  1.0000
##  M_M high - L_S low  -0.255157 10.06 Inf  -0.025  1.0000
##  M_M high - M low    -0.095225  9.72 Inf  -0.010  1.0000
##  M_M high - M_M low  -0.156604  8.04 Inf  -0.019  1.0000
##  M_M high - S low    -0.319584 11.16 Inf  -0.029  1.0000
##  M_M high - S_L low  -0.054164  9.53 Inf  -0.006  1.0000
##  M_M high - S_S low  -0.151697  8.65 Inf  -0.018  1.0000
##  S high - S_L high    0.182568 13.87 Inf   0.013  1.0000
##  S high - S_S high    0.189170 11.58 Inf   0.016  1.0000
##  S high - L low       0.099735 21.90 Inf   0.005  1.0000
##  S high - L_L low     0.010911 20.76 Inf   0.001  1.0000
##  S high - L_S low    -0.078544 20.35 Inf  -0.004  1.0000
##  S high - M low       0.081388 19.44 Inf   0.004  1.0000
##  S high - M_M low     0.020009 18.46 Inf   0.001  1.0000
##  S high - S low      -0.142971 13.67 Inf  -0.010  1.0000
##  S high - S_L low     0.122449 17.07 Inf   0.007  1.0000
##  S high - S_S low     0.024916 13.76 Inf   0.002  1.0000
##  S_L high - S_S high  0.006602  9.71 Inf   0.001  1.0000
##  S_L high - L low    -0.082834 15.48 Inf  -0.005  1.0000
##  S_L high - L_L low  -0.171657 14.06 Inf  -0.012  1.0000
##  S_L high - L_S low  -0.261113 14.20 Inf  -0.018  1.0000
##  S_L high - M low    -0.101180 13.50 Inf  -0.007  1.0000
##  S_L high - M_M low  -0.162560 12.21 Inf  -0.013  1.0000
##  S_L high - S low    -0.325540 10.99 Inf  -0.030  1.0000
##  S_L high - S_L low  -0.060120 12.01 Inf  -0.005  1.0000
##  S_L high - S_S low  -0.157652  9.60 Inf  -0.016  1.0000
##  S_S high - L low    -0.089436 16.16 Inf  -0.006  1.0000
##  S_S high - L_L low  -0.178259 14.76 Inf  -0.012  1.0000
##  S_S high - L_S low  -0.267715 14.69 Inf  -0.018  1.0000
##  S_S high - M low    -0.107782 13.88 Inf  -0.008  1.0000
##  S_S high - M_M low  -0.169162 12.57 Inf  -0.013  1.0000
##  S_S high - S low    -0.332142  9.64 Inf  -0.034  1.0000
##  S_S high - S_L low  -0.066722 11.81 Inf  -0.006  1.0000
##  S_S high - S_S low  -0.164254  8.64 Inf  -0.019  1.0000
##  L low - L_L low     -0.088824  9.48 Inf  -0.009  1.0000
##  L low - L_S low     -0.178279 11.09 Inf  -0.016  1.0000
##  L low - M low       -0.018346 11.44 Inf  -0.002  1.0000
##  L low - M_M low     -0.079726 10.06 Inf  -0.008  1.0000
##  L low - S low       -0.242706 15.71 Inf  -0.015  1.0000
##  L low - S_L low      0.022714 12.44 Inf   0.002  1.0000
##  L low - S_S low     -0.074818 13.45 Inf  -0.006  1.0000
##  L_L low - L_S low   -0.089455  9.54 Inf  -0.009  1.0000
##  L_L low - M low      0.070477  9.82 Inf   0.007  1.0000
##  L_L low - M_M low    0.009098  8.14 Inf   0.001  1.0000
##  L_L low - S low     -0.153882 14.35 Inf  -0.011  1.0000
##  L_L low - S_L low    0.111538 10.91 Inf   0.010  1.0000
##  L_L low - S_S low    0.014005 11.81 Inf   0.001  1.0000
##  L_S low - M low      0.159933 11.00 Inf   0.015  1.0000
##  L_S low - M_M low    0.098553  9.53 Inf   0.010  1.0000
##  L_S low - S low     -0.064427 14.47 Inf  -0.004  1.0000
##  L_S low - S_L low    0.200993 11.69 Inf   0.017  1.0000
##  L_S low - S_S low    0.103460 12.13 Inf   0.009  1.0000
##  M low - M_M low     -0.061380  9.42 Inf  -0.007  1.0000
##  M low - S low       -0.224360 13.83 Inf  -0.016  1.0000
##  M low - S_L low      0.041060 11.43 Inf   0.004  1.0000
##  M low - S_S low     -0.056472 11.41 Inf  -0.005  1.0000
##  M_M low - S low     -0.162980 12.56 Inf  -0.013  1.0000
##  M_M low - S_L low    0.102440  9.97 Inf   0.010  1.0000
##  M_M low - S_S low    0.004908  9.91 Inf   0.000  1.0000
##  S low - S_L low      0.265420 12.12 Inf   0.022  1.0000
##  S low - S_S low      0.167887  9.84 Inf   0.017  1.0000
##  S_L low - S_S low   -0.097532 10.20 Inf  -0.010  1.0000
## 
## Results are given on the log (not the response) scale. 
## P value adjustment: tukey method for comparing a family of 16 estimates
high_L = c(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
high_L_L = c(0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
high_L_S = c(0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
high_M = c(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
high_M_M = c(0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
high_S = c(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
high_S_L = c(0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0)
high_S_S = c(0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0)
low_L = c(rep(0,8), 1, rep(0,7))
low_L_L = c(rep(0,9), 1, rep(0,6))
low_L_S = c(rep(0,10), 1, rep(0,5))
low_M = c(rep(0,11), 1, rep(0,4))
low_M_M = c(rep(0,12), 1, rep(0,3))
low_S = c(rep(0,13), 1, rep(0,2))
low_S_L = c(rep(0,14), 1, rep(0,1))
low_S_S = c(rep(0,15), 1)

n_of_digits = 3
contrasts = contrast(emmeans_output, 
                     method = list("high S_L - S" = high_S_L - high_S,
                                   "high S_L - S_S" = high_S_L - high_S_S,
                                   "high S_S - S" = high_S_S - high_S,
                                   "high M_M - M" = high_M_M - high_M,
                                   "high L_S - L" = high_L_S - high_L,
                                   "high L_S - L_L" = high_L_S - high_L_L,
                                   "high L_L - L" = high_L_L - high_L,
                                   "low S_L - S" = low_S_L - low_S,
                                   "low S_L - S_S" = low_S_L - low_S_S,
                                   "low S_S - S" = low_S_S - low_S,
                                   "low M_M - M" = low_M_M - low_M,
                                   "low L_S - L" = low_L_S - low_L,
                                   "low L_S - L_L" = low_L_S - low_L_L,
                                   "low L_L - L" = low_L_L - low_L)) %>%
  as.data.frame() %>%
  mutate(p.value = round(p.value, digits = n_of_digits),
         estimate = round(estimate, digits = n_of_digits),
         SE = round(SE, digits = n_of_digits),
         df = round(df, digits = n_of_digits),
         z.ratio = round(z.ratio, digits = n_of_digits),
         e = "",
         e = ifelse(p.value > 0.1, 
                           "",
                           e),
         e = ifelse(p.value < 0.05, 
                           "*",
                           e),
         e = ifelse(p.value < 0.01, 
                           "**",
                           e),
         e = ifelse(p.value < 0.001, 
                           "***",
                           e)) %>%
  rename(" " = e)
# --- SHOW ECOSYSTEM TYPE CONSTRASTS --- #
contrasts
##          contrast estimate     SE  df z.ratio p.value  
## 1    high S_L - S   -0.183 13.873 Inf  -0.013   0.989  
## 2  high S_L - S_S    0.007  9.706 Inf   0.001   0.999  
## 3    high S_S - S   -0.189 11.584 Inf  -0.016   0.987  
## 4    high M_M - M    0.001  9.562 Inf   0.000   1.000  
## 5    high L_S - L    0.117 10.968 Inf   0.011   0.992  
## 6  high L_S - L_L    0.075  9.564 Inf   0.008   0.994  
## 7    high L_L - L    0.041  9.546 Inf   0.004   0.997  
## 8     low S_L - S   -0.265 12.123 Inf  -0.022   0.983  
## 9   low S_L - S_S   -0.098 10.204 Inf  -0.010   0.992  
## 10    low S_S - S   -0.168  9.839 Inf  -0.017   0.986  
## 11    low M_M - M    0.061  9.423 Inf   0.007   0.995  
## 12    low L_S - L    0.178 11.095 Inf   0.016   0.987  
## 13  low L_S - L_L    0.089  9.538 Inf   0.009   0.993  
## 14    low L_L - L    0.089  9.479 Inf   0.009   0.993


# --- CONSTRUCT RESIDUALS VS FITTED VALUES PLOT --- #

res_vs_fit = data_for_analysis %>%
    mutate(predicted = fitted(full_model),
           residuals = resid(full_model)) %>%
    plot_ly(x = ~predicted,
            y = ~residuals,
            type = "scatter",
            mode = "markers",
            marker = list(size = 5, color = "#4C78A8"),
            text = paste(" ID: ", 
                         data_for_analysis$culture_ID, 
                         "<br>",
                         "Day: ", 
                         data_for_analysis$day, 
                         "<br>",
                         "Patch Type: ", 
                         data_for_analysis$ecosystem_type, 
                         "<br>",
                         "Biomass density: ", 
                         round(data_for_analysis$bioarea_mm2_per_ml, digits = 2), 
                         "<br>",
                         "Species richness: ", 
                         data_for_analysis$species_richness, 
                         "<br>"),
            hoverinfo = "text") %>%
    plotly::layout(title = "Residuals vs. Fitted Values",
                   xaxis = list(title = "Fitted Values"),
                   yaxis = list(title = "Residuals"))
# --- PLOT RESIDUALS --- #

qqnorm(resid(full_model))
qqline(resid(full_model))

res_vs_fit

\(S\) vs \(M\) vs \(L\)

ecosystem_type_selected = c("Small unconnected",
                            "Medium unconnected",
                            "Large unconnected")

Shannon

response_variable_selected = "shannon"

We want to know whether the size of ecosystems influenced this response variable. We only look at unconnected ecosystems so that the effects of connection don’t confound the effects of ecosystem size. We first start from plotting how this response variable changed in different sizes throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(metaecosystem == "no",
         time_point %in% time_points_model,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- CALCULATE BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines,
         !is.na(!!sym(response_variable_selected))) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how ecosystem size influenced this variable. To study the effects of ecosystem size we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of size with time (Response variable ~ size * day + (day | culture ID)), the reduced model contains the size but without the interaction with time (Response variable ~ size + day + (day | culture ID)), and the null model doesn’t contain the size at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem size had an effect.

# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_size * scale(day) +
                    scale(water_addition_ml) * scale(day) + 
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE)
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, :
## Model failed to converge with max|grad| = 0.0166906 (tol = 0.002, component 1)
reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_size + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) + 
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE)
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, :
## Model failed to converge with max|grad| = 0.0240792 (tol = 0.002, component 1)
null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) + 
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE)
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, :
## Model failed to converge with max|grad| = 0.00237388 (tol = 0.002, component 1)


Full model vs null model

Click to view the results of the ANOVA comparison between full and null model.
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value         evidence
## 1      -18 < 0.001 **** very strong
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_size * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## 
##      AIC      BIC   logLik deviance df.resid 
##     53.8     86.0    -12.9     25.8       60 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.77  -0.59  -0.07   0.45   2.83 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 8e-02    0.28          
##             day         2e-04    0.01     -0.97
##  Residual               7e-02    0.27          
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             1.46       0.08 17.14    19.3    5e-13
## ecosystem_sizeMedium                   -0.18       0.09 12.40    -1.9     0.08
## ecosystem_sizeSmall                    -0.65       0.11 12.74    -5.8    7e-05
## scale(day)                             -0.09       0.08 18.83    -1.1     0.27
## scale(water_addition_ml)               -0.01       0.07 57.38    -0.2     0.83
## scale(baseline)                         0.03       0.05 11.54     0.7     0.52
## ecosystem_sizeMedium:scale(day)         0.24       0.10 16.19     2.5     0.02
## ecosystem_sizeSmall:scale(day)         -0.14       0.12 15.85    -1.2     0.26
## scale(day):scale(water_addition_ml)    -0.07       0.06 64.32    -1.1     0.27
## scale(day):scale(baseline)             -0.06       0.05 14.21    -1.3     0.21
##                                        
## (Intercept)                         ***
## ecosystem_sizeMedium                .  
## ecosystem_sizeSmall                 ***
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                        
## ecosystem_sizeMedium:scale(day)     *  
## ecosystem_sizeSmall:scale(day)         
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecsy_M ecsy_S scl(d) sc(__) scl(b) e_M:() e_S:() s():(_
## ecsystm_szM -0.668                                                        
## ecsystm_szS -0.721  0.509                                                 
## scale(day)  -0.010  0.039  0.005                                          
## scl(wtr_d_)  0.237  0.102  0.030  0.221                                   
## scale(bsln) -0.374  0.168  0.592 -0.021 -0.024                            
## ecsyst_M:()  0.083  0.024 -0.012 -0.703  0.069 -0.005                     
## ecsyst_S:() -0.026  0.005  0.093 -0.738 -0.079  0.069  0.495              
## scl(d):(__)  0.417 -0.037 -0.085 -0.026  0.811 -0.056  0.238  0.024       
## scl(dy):s() -0.041  0.007  0.072 -0.372 -0.050  0.104  0.157  0.597 -0.030
## optimizer (nloptwrap) convergence code: 0 (OK)
## Model failed to converge with max|grad| = 0.0166906 (tol = 0.002, component 1)
Click to view the full model residual plots
# --- SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Click to view the results of the ANOVA comparison between reduced and null model.
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value         evidence
## 1    -12.5 < 0.001 **** very strong
Reduced model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_size + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## 
##      AIC      BIC   logLik deviance df.resid 
##     59.3     86.9    -17.6     35.3       62 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.95  -0.66  -0.02   0.35   2.89 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 3e-01    0.58          
##             day         9e-04    0.03     -1.00
##  Residual               7e-02    0.27          
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error     df t value Pr(>|t|)
## (Intercept)                            1.449      0.073 17.525    20.0    2e-13
## ecosystem_sizeMedium                  -0.177      0.087 12.355    -2.0     0.06
## ecosystem_sizeSmall                   -0.624      0.107 13.025    -5.8    6e-05
## scale(day)                            -0.048      0.058 18.053    -0.8     0.42
## scale(water_addition_ml)              -0.021      0.069 56.816    -0.3     0.76
## scale(baseline)                        0.038      0.043 11.523     0.9     0.40
## scale(day):scale(water_addition_ml)   -0.079      0.060 64.295    -1.3     0.19
## scale(day):scale(baseline)            -0.003      0.054 13.857    -0.1     0.96
##                                        
## (Intercept)                         ***
## ecosystem_sizeMedium                .  
## ecosystem_sizeSmall                 ***
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecsy_M ecsy_S scl(d) sc(__) scl(b) s():(_
## ecsystm_szM -0.666                                          
## ecsystm_szS -0.718  0.515                                   
## scale(day)  -0.004  0.081  0.077                            
## scl(wtr_d_)  0.244  0.111  0.042  0.295                     
## scale(bsln) -0.373  0.171  0.593  0.022 -0.020              
## scl(d):(__)  0.443 -0.046 -0.092  0.118  0.806 -0.059       
## scl(dy):s() -0.008  0.008  0.006  0.010  0.015  0.024 -0.004
## optimizer (nloptwrap) convergence code: 0 (OK)
## Model failed to converge with max|grad| = 0.0240792 (tol = 0.002, component 1)
Click to view the reduced model residual plots
# --- SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Biomass

response_variable_selected = "bioarea_mm2_per_ml"

We want to know whether the size of ecosystems influenced this response variable. We only look at unconnected ecosystems so that the effects of connection don’t confound the effects of ecosystem size. We first start from plotting how this response variable changed in different sizes throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(metaecosystem == "no",
         time_point %in% time_points_model,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- CALCULATE BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines,
         !is.na(!!sym(response_variable_selected))) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how ecosystem size influenced this variable. To study the effects of ecosystem size we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of size with time (Response variable ~ size * day + (day | culture ID)), the reduced model contains the size but without the interaction with time (Response variable ~ size + day + (day | culture ID)), and the null model doesn’t contain the size at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem size had an effect.

# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_size * scale(day) +
                    scale(water_addition_ml) * scale(day) + 
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE)

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_size + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) + 
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE)
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, :
## Model failed to converge with max|grad| = 0.249836 (tol = 0.002, component 1)
null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) + 
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE)


Full model vs null model

Click to view the results of the ANOVA comparison between full and null model.
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value         evidence
## 1    -16.8 < 0.001 **** very strong
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_size * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## 
##      AIC      BIC   logLik deviance df.resid 
##    186.6    219.1    -79.3    158.6       61 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.32  -0.43   0.02   0.55   2.27 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 2e-01    0.489         
##             day         3e-05    0.005    -1.00
##  Residual               4e-01    0.626         
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             3.20       0.23 18.94    14.1    2e-11
## ecosystem_sizeMedium                   -1.65       0.33 15.87    -4.9    2e-04
## ecosystem_sizeSmall                    -2.36       0.32 15.73    -7.4    2e-06
## scale(day)                             -0.55       0.15 57.73    -3.8    4e-04
## scale(water_addition_ml)                0.23       0.16 62.34     1.5      0.1
## scale(baseline)                         0.06       0.16 15.30     0.4      0.7
## ecosystem_sizeMedium:scale(day)        -0.04       0.21 57.24    -0.2      0.8
## ecosystem_sizeSmall:scale(day)          0.09       0.19 56.48     0.5      0.6
## scale(day):scale(water_addition_ml)    -0.03       0.14 65.00    -0.3      0.8
## scale(day):scale(baseline)              0.04       0.09 56.25     0.4      0.7
##                                        
## (Intercept)                         ***
## ecosystem_sizeMedium                ***
## ecosystem_sizeSmall                 ***
## scale(day)                          ***
## scale(water_addition_ml)               
## scale(baseline)                        
## ecosystem_sizeMedium:scale(day)        
## ecosystem_sizeSmall:scale(day)         
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecsy_M ecsy_S scl(d) sc(__) scl(b) e_M:() e_S:() s():(_
## ecsystm_szM -0.645                                                        
## ecsystm_szS -0.644  0.327                                                 
## scale(day)  -0.146  0.117  0.105                                          
## scl(wtr_d_)  0.182  0.077  0.019  0.237                                   
## scale(bsln)  0.054 -0.404  0.292 -0.006 -0.027                            
## ecsyst_M:()  0.168 -0.108 -0.064 -0.664  0.124  0.024                     
## ecsyst_S:()  0.089 -0.058 -0.108 -0.669 -0.106 -0.023  0.346              
## scl(d):(__)  0.307 -0.005 -0.054 -0.059  0.817 -0.029  0.303  0.035       
## scl(dy):s() -0.030  0.031 -0.022  0.050 -0.087 -0.080 -0.399  0.287 -0.090
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Click to view the full model residual plots
# --- SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Click to view the results of the ANOVA comparison between reduced and null model.
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value         evidence
## 1    -20.4 < 0.001 **** very strong
Reduced model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_size + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## 
##      AIC      BIC   logLik deviance df.resid 
##    183.0    210.8    -79.5    159.0       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.27  -0.45   0.02   0.49   2.43 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 2e-01    0.483         
##             day         2e-05    0.005    -1.00
##  Residual               4e-01    0.628         
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error     df t value Pr(>|t|)
## (Intercept)                            3.202      0.223 18.333    14.3    2e-11
## ecosystem_sizeMedium                  -1.655      0.331 15.827    -5.0    1e-04
## ecosystem_sizeSmall                   -2.351      0.316 15.677    -7.4    2e-06
## scale(day)                            -0.534      0.086 58.725    -6.2    5e-08
## scale(water_addition_ml)               0.250      0.155 62.386     1.6      0.1
## scale(baseline)                        0.068      0.155 15.423     0.4      0.7
## scale(day):scale(water_addition_ml)   -0.019      0.132 64.577    -0.1      0.9
## scale(day):scale(baseline)             0.008      0.074 56.459     0.1      0.9
##                                        
## (Intercept)                         ***
## ecosystem_sizeMedium                ***
## ecosystem_sizeSmall                 ***
## scale(day)                          ***
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecsy_M ecsy_S scl(d) sc(__) scl(b) s():(_
## ecsystm_szM -0.640                                          
## ecsystm_szS -0.643  0.322                                   
## scale(day)  -0.031  0.062  0.034                            
## scl(wtr_d_)  0.173  0.089  0.014  0.430                     
## scale(bsln)  0.051 -0.405  0.293 -0.010 -0.036              
## scl(d):(__)  0.279  0.027 -0.044  0.194  0.825 -0.041       
## scl(dy):s()  0.029 -0.003 -0.008 -0.006  0.044 -0.066  0.086
## optimizer (nloptwrap) convergence code: 0 (OK)
## Model failed to converge with max|grad| = 0.249836 (tol = 0.002, component 1)
Click to view the reduced model residual plots
# --- SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Richness

response_variable_selected = "species_richness"

We want to know whether the size of ecosystems influenced this response variable. We only look at unconnected ecosystems so that the effects of connection don’t confound the effects of ecosystem size. We first start from plotting how this response variable changed in different sizes throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(metaecosystem == "no",
         time_point %in% time_points_model,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- CALCULATE BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines,
         !is.na(!!sym(response_variable_selected))) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how ecosystem size influenced this variable. To study the effects of ecosystem size we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of size with time (Response variable ~ size * day + (day | culture ID)), the reduced model contains the size but without the interaction with time (Response variable ~ size + day + (day | culture ID)), and the null model doesn’t contain the size at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem size had an effect.

# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_size * scale(day) +
                    scale(water_addition_ml) * scale(day) + 
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE)
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, :
## Model failed to converge with max|grad| = 0.202233 (tol = 0.002, component 1)
reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_size + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) + 
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE)
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, :
## Model failed to converge with max|grad| = 0.0531313 (tol = 0.002, component 1)
null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) + 
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE)


Full model vs null model

Click to view the results of the ANOVA comparison between full and null model.
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value         evidence
## 1    -16.1 < 0.001 **** very strong
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_size * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## 
##      AIC      BIC   logLik deviance df.resid 
##    285.8    318.3   -128.9    257.8       61 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -1.96  -0.63  -0.06   0.55   2.78 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e-01    4e-01         
##             day         5e-07    7e-04    -0.35
##  Residual               2e+00    1e+00         
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             6.80       0.35 19.94    19.2    2e-14
## ecosystem_sizeMedium                   -1.68       0.45 14.98    -3.7    0.002
## ecosystem_sizeSmall                    -3.76       0.52 14.48    -7.2    4e-06
## scale(day)                              0.21       0.31 60.49     0.7    0.507
## scale(water_addition_ml)                0.05       0.32 68.17     0.1    0.887
## scale(baseline)                         0.24       0.23 13.79     1.0    0.315
## ecosystem_sizeMedium:scale(day)        -0.10       0.40 60.53    -0.3    0.802
## ecosystem_sizeSmall:scale(day)         -0.97       0.45 59.51    -2.2    0.034
## scale(day):scale(water_addition_ml)    -0.28       0.28 70.26    -1.0    0.315
## scale(day):scale(baseline)             -0.17       0.20 59.30    -0.9    0.386
##                                        
## (Intercept)                         ***
## ecosystem_sizeMedium                ** 
## ecosystem_sizeSmall                 ***
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                        
## ecosystem_sizeMedium:scale(day)        
## ecosystem_sizeSmall:scale(day)      *  
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecsy_M ecsy_S scl(d) sc(__) scl(b) e_M:() e_S:() s():(_
## ecsystm_szM -0.621                                                        
## ecsystm_szS -0.681  0.386                                                 
## scale(day)  -0.091  0.102  0.075                                          
## scl(wtr_d_)  0.238  0.104  0.029  0.256                                   
## scale(bsln) -0.228 -0.098  0.527  0.008 -0.013                            
## ecsyst_M:()  0.155 -0.055 -0.055 -0.657  0.100 -0.011                     
## ecsyst_S:()  0.042 -0.046 -0.034 -0.710 -0.113 -0.004  0.388              
## scl(d):(__)  0.404 -0.019 -0.068 -0.030  0.818 -0.026  0.289  0.015       
## scl(dy):s() -0.021 -0.006 -0.002 -0.224 -0.076  0.000 -0.106  0.523 -0.066
## optimizer (nloptwrap) convergence code: 0 (OK)
## Model failed to converge with max|grad| = 0.202233 (tol = 0.002, component 1)
Click to view the full model residual plots
# --- SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Click to view the results of the ANOVA comparison between reduced and null model.
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value         evidence
## 1    -15.4 < 0.001 **** very strong
Reduced model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_size + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## 
##      AIC      BIC   logLik deviance df.resid 
##    286.6    314.4   -131.3    262.6       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -1.83  -0.62   0.01   0.54   2.70 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 3e-03    0.06          
##             day         4e-04    0.02     -0.98
##  Residual               2e+00    1.35          
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             6.78       0.35 20.42    19.3    1e-14
## ecosystem_sizeMedium                   -1.71       0.45 16.23    -3.8    0.002
## ecosystem_sizeSmall                    -3.70       0.52 15.89    -7.1    3e-06
## scale(day)                             -0.19       0.19 49.77    -1.0    0.316
## scale(water_addition_ml)               -0.05       0.33 69.14    -0.1    0.885
## scale(baseline)                         0.26       0.23 14.95     1.2    0.268
## scale(day):scale(water_addition_ml)    -0.31       0.28 70.21    -1.1    0.271
## scale(day):scale(baseline)              0.09       0.16 40.82     0.6    0.565
##                                        
## (Intercept)                         ***
## ecosystem_sizeMedium                ** 
## ecosystem_sizeSmall                 ***
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecsy_M ecsy_S scl(d) sc(__) scl(b) s():(_
## ecsystm_szM -0.627                                          
## ecsystm_szS -0.679  0.390                                   
## scale(day)   0.035  0.099  0.065                            
## scl(wtr_d_)  0.233  0.104  0.044  0.425                     
## scale(bsln) -0.224 -0.096  0.525  0.006 -0.003              
## scl(d):(__)  0.400 -0.027 -0.057  0.201  0.829 -0.017       
## scl(dy):s()  0.011  0.005  0.002  0.019  0.046  0.066  0.038
## optimizer (nloptwrap) convergence code: 0 (OK)
## Model failed to converge with max|grad| = 0.0531313 (tol = 0.002, component 1)
Click to view the reduced model residual plots
# --- SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Evenness

response_variable_selected = "evenness_pielou"

We want to know whether the size of ecosystems influenced this response variable. We only look at unconnected ecosystems so that the effects of connection don’t confound the effects of ecosystem size. We first start from plotting how this response variable changed in different sizes throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(metaecosystem == "no",
         time_point %in% time_points_model,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- CALCULATE BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines,
         !is.na(!!sym(response_variable_selected))) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how ecosystem size influenced this variable. To study the effects of ecosystem size we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of size with time (Response variable ~ size * day + (day | culture ID)), the reduced model contains the size but without the interaction with time (Response variable ~ size + day + (day | culture ID)), and the null model doesn’t contain the size at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem size had an effect.

# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_size * scale(day) +
                    scale(water_addition_ml) * scale(day) + 
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE)

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_size + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) + 
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE)

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) + 
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE)


Full model vs null model

Click to view the results of the ANOVA comparison between full and null model.
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1     -0.5   0.074   * weak
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_size * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## 
##      AIC      BIC   logLik deviance df.resid 
##    -56.1    -24.2     42.1    -84.1       58 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -4.2   -0.5    0.1    0.7    2.5 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 9e-03    0.094         
##             day         4e-05    0.006    -1.00
##  Residual               2e-02    0.128         
## Number of obs: 72, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error     df t value Pr(>|t|)
## (Intercept)                            0.773      0.036 28.845    21.3   <2e-16
## ecosystem_sizeMedium                   0.026      0.045 21.545     0.6     0.56
## ecosystem_sizeSmall                   -0.005      0.052 22.287    -0.1     0.93
## scale(day)                            -0.072      0.037 27.372    -2.0     0.06
## scale(water_addition_ml)              -0.034      0.034 65.834    -1.0     0.31
## scale(baseline)                       -0.004      0.021 20.106    -0.2     0.84
## ecosystem_sizeMedium:scale(day)        0.131      0.048 23.662     2.7     0.01
## ecosystem_sizeSmall:scale(day)         0.004      0.054 21.872     0.1     0.94
## scale(day):scale(water_addition_ml)   -0.031      0.029 65.410    -1.1     0.29
## scale(day):scale(baseline)            -0.009      0.022 20.037    -0.4     0.69
##                                        
## (Intercept)                         ***
## ecosystem_sizeMedium                   
## ecosystem_sizeSmall                    
## scale(day)                          .  
## scale(water_addition_ml)               
## scale(baseline)                        
## ecosystem_sizeMedium:scale(day)     *  
## ecosystem_sizeSmall:scale(day)         
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecsy_M ecsy_S scl(d) sc(__) scl(b) e_M:() e_S:() s():(_
## ecsystm_szM -0.692                                                        
## ecsystm_szS -0.708  0.564                                                 
## scale(day)   0.130 -0.069 -0.094                                          
## scl(wtr_d_)  0.261  0.090  0.036  0.237                                   
## scale(bsln) -0.393  0.292  0.539 -0.080 -0.052                            
## ecsyst_M:() -0.020  0.174  0.075 -0.726  0.068  0.046                     
## ecsyst_S:() -0.116  0.092  0.241 -0.737 -0.061  0.129  0.559              
## scl(d):(__)  0.427 -0.039 -0.070  0.000  0.831 -0.078  0.230  0.045       
## scl(dy):s() -0.084  0.056  0.125 -0.391 -0.051  0.249  0.287  0.536 -0.015
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Click to view the full model residual plots
# --- SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Click to view the results of the ANOVA comparison between reduced and null model.
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      3.9    0.93     none
Reduced model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_size + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## 
##      AIC      BIC   logLik deviance df.resid 
##    -51.7    -24.4     37.9    -75.7       60 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -3.8   -0.5    0.1    0.6    2.6 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 3e-02    0.18          
##             day         1e-04    0.01     -1.00
##  Residual               2e-02    0.13          
## Number of obs: 72, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error     df t value Pr(>|t|)
## (Intercept)                            0.777      0.038 28.795    20.3   <2e-16
## ecosystem_sizeMedium                  -0.016      0.046 29.047    -0.3     0.74
## ecosystem_sizeSmall                    0.002      0.052 34.204     0.0     0.96
## scale(day)                            -0.026      0.025 21.017    -1.0     0.32
## scale(water_addition_ml)              -0.047      0.034 62.999    -1.4     0.17
## scale(baseline)                       -0.003      0.023 15.912    -0.1     0.89
## scale(day):scale(water_addition_ml)   -0.050      0.029 64.319    -1.7     0.09
## scale(day):scale(baseline)            -0.009      0.023 15.145    -0.4     0.70
##                                        
## (Intercept)                         ***
## ecosystem_sizeMedium                   
## ecosystem_sizeSmall                    
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml) .  
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecsy_M ecsy_S scl(d) sc(__) scl(b) s():(_
## ecsystm_szM -0.703                                          
## ecsystm_szS -0.691  0.588                                   
## scale(day)   0.207  0.091  0.100                            
## scl(wtr_d_)  0.250  0.068  0.072  0.365                     
## scale(bsln) -0.356  0.280  0.496  0.008 -0.035              
## scl(d):(__)  0.444 -0.117 -0.076  0.194  0.837 -0.079       
## scl(dy):s() -0.020  0.009 -0.006 -0.004 -0.019  0.389 -0.035
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Click to view the reduced model residual plots
# --- SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Median Size

response_variable_selected = "median_body_area_µm2"

We want to know whether the size of ecosystems influenced this response variable. We only look at unconnected ecosystems so that the effects of connection don’t confound the effects of ecosystem size. We first start from plotting how this response variable changed in different sizes throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(metaecosystem == "no",
         time_point %in% time_points_model,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- CALCULATE BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines,
         !is.na(!!sym(response_variable_selected))) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how ecosystem size influenced this variable. To study the effects of ecosystem size we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of size with time (Response variable ~ size * day + (day | culture ID)), the reduced model contains the size but without the interaction with time (Response variable ~ size + day + (day | culture ID)), and the null model doesn’t contain the size at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem size had an effect.

# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_size * scale(day) +
                    scale(water_addition_ml) * scale(day) + 
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE)

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_size + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) + 
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE)

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) + 
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE)


Full model vs null model

Click to view the results of the ANOVA comparison between full and null model.
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      5.8   0.699     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_size * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## 
##      AIC      BIC   logLik deviance df.resid 
##   1151.4   1183.7   -561.7   1123.4       60 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.89  -0.56  -0.09   0.52   2.36 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e+04    110           
##             day         5e+01      7      -1.00
##  Residual               2e+05    477           
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error   df t value Pr(>|t|)
## (Intercept)                             3647        113   60    32.4   <2e-16
## ecosystem_sizeMedium                     104        146   51     0.7      0.5
## ecosystem_sizeSmall                        5        167   51     0.0      1.0
## scale(day)                               -67        113   34    -0.6      0.6
## scale(water_addition_ml)                  -4        116   72     0.0      1.0
## scale(baseline)                           14         78   49     0.2      0.9
## ecosystem_sizeMedium:scale(day)          130        151   27     0.9      0.4
## ecosystem_sizeSmall:scale(day)           203        169   25     1.2      0.2
## scale(day):scale(water_addition_ml)      -20        101   72    -0.2      0.8
## scale(day):scale(baseline)                54         80   24     0.7      0.5
##                                        
## (Intercept)                         ***
## ecosystem_sizeMedium                   
## ecosystem_sizeSmall                    
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                        
## ecosystem_sizeMedium:scale(day)        
## ecosystem_sizeSmall:scale(day)         
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecsy_M ecsy_S scl(d) sc(__) scl(b) e_M:() e_S:() s():(_
## ecsystm_szM -0.577                                                        
## ecsystm_szS -0.645  0.280                                                 
## scale(day)  -0.109  0.114  0.089                                          
## scl(wtr_d_)  0.266  0.129  0.022  0.247                                   
## scale(bsln) -0.168 -0.267  0.535  0.002 -0.048                            
## ecsyst_M:()  0.156 -0.044 -0.059 -0.628  0.085 -0.031                     
## ecsyst_S:()  0.073 -0.050 -0.040 -0.675 -0.073 -0.012  0.295              
## scl(d):(__)  0.464 -0.011 -0.101 -0.048  0.810 -0.067  0.256  0.071       
## scl(dy):s()  0.032 -0.032 -0.024 -0.179 -0.008  0.041 -0.237  0.529  0.049
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Click to view the full model residual plots
# --- SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Click to view the results of the ANOVA comparison between reduced and null model.
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      3.4   0.758     none
Reduced model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_size + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## 
##      AIC      BIC   logLik deviance df.resid 
##   1149.1   1176.7   -562.5   1125.1       62 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.8   -0.6   -0.1    0.5    2.4 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 5e+04    225           
##             day         2e+02     13      -1.00
##  Residual               2e+05    477           
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error     df t value Pr(>|t|)
## (Intercept)                           3635.3      112.6   47.3    32.3   <2e-16
## ecosystem_sizeMedium                   108.8      147.1   44.3     0.7      0.5
## ecosystem_sizeSmall                      7.6      168.2   44.1     0.0      1.0
## scale(day)                              48.6       68.2   23.6     0.7      0.5
## scale(water_addition_ml)                -0.2      115.9   72.0     0.0      1.0
## scale(baseline)                         16.7       78.6   44.4     0.2      0.8
## scale(day):scale(water_addition_ml)    -37.6       98.3   73.3    -0.4      0.7
## scale(day):scale(baseline)              23.1       61.7   17.7     0.4      0.7
##                                        
## (Intercept)                         ***
## ecosystem_sizeMedium                   
## ecosystem_sizeSmall                    
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecsy_M ecsy_S scl(d) sc(__) scl(b) s():(_
## ecsystm_szM -0.581                                          
## ecsystm_szS -0.645  0.281                                   
## scale(day)   0.021  0.112  0.070                            
## scl(wtr_d_)  0.261  0.127  0.027  0.417                     
## scale(bsln) -0.165 -0.268  0.533 -0.032 -0.045              
## scl(d):(__)  0.449 -0.009 -0.091  0.191  0.822 -0.060       
## scl(dy):s()  0.068 -0.025 -0.032 -0.017  0.097  0.073  0.149
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Click to view the reduced model residual plots
# --- SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Auto/Hetero

response_variable_selected = "auto_hetero_ratio"

We want to know whether the size of ecosystems influenced this response variable. We only look at unconnected ecosystems so that the effects of connection don’t confound the effects of ecosystem size. We first start from plotting how this response variable changed in different sizes throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(metaecosystem == "no",
         time_point %in% time_points_model,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- CALCULATE BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines,
         !is.na(!!sym(response_variable_selected))) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how ecosystem size influenced this variable. To study the effects of ecosystem size we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of size with time (Response variable ~ size * day + (day | culture ID)), the reduced model contains the size but without the interaction with time (Response variable ~ size + day + (day | culture ID)), and the null model doesn’t contain the size at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem size had an effect.

# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_size * scale(day) +
                    scale(water_addition_ml) * scale(day) + 
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE)

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_size + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) + 
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE)

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) + 
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE)


Full model vs null model

Click to view the results of the ANOVA comparison between full and null model.
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      4.4   0.458     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_size * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## 
##      AIC      BIC   logLik deviance df.resid 
##    -47.7    -15.4     37.8    -75.7       60 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.1   -0.6   -0.2    0.3    3.4 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 2e-02    0.140         
##             day         8e-05    0.009    -1.00
##  Residual               2e-02    0.134         
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error     df t value Pr(>|t|)
## (Intercept)                            2e-01      4e-02  3e+01     3.9    6e-04
## ecosystem_sizeMedium                   2e-02      5e-02  2e+01     0.4      0.7
## ecosystem_sizeSmall                   -3e-02      5e-02  2e+01    -0.7      0.5
## scale(day)                             2e-04      4e-02  2e+01     0.0      1.0
## scale(water_addition_ml)               2e-02      3e-02  7e+01     0.6      0.6
## scale(baseline)                       -9e-03      2e-02  2e+01    -0.4      0.7
## ecosystem_sizeMedium:scale(day)        7e-02      6e-02  2e+01     1.2      0.2
## ecosystem_sizeSmall:scale(day)         6e-02      5e-02  1e+01     1.2      0.3
## scale(day):scale(water_addition_ml)    4e-04      3e-02  6e+01     0.0      1.0
## scale(day):scale(baseline)            -1e-02      2e-02  1e+01    -0.4      0.7
##                                        
## (Intercept)                         ***
## ecosystem_sizeMedium                   
## ecosystem_sizeSmall                    
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                        
## ecosystem_sizeMedium:scale(day)        
## ecosystem_sizeSmall:scale(day)         
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecsy_M ecsy_S scl(d) sc(__) scl(b) e_M:() e_S:() s():(_
## ecsystm_szM -0.702                                                        
## ecsystm_szS -0.692  0.555                                                 
## scale(day)   0.253 -0.199 -0.191                                          
## scl(wtr_d_)  0.237  0.080  0.052  0.170                                   
## scale(bsln) -0.306  0.442  0.246 -0.145 -0.030                            
## ecsyst_M:() -0.140  0.328  0.161 -0.733  0.106  0.175                     
## ecsyst_S:() -0.198  0.174  0.353 -0.714 -0.023  0.107  0.549              
## scl(d):(__)  0.380 -0.011 -0.044 -0.038  0.823  0.011  0.224  0.064       
## scl(dy):s() -0.103  0.178  0.106 -0.302  0.092  0.363  0.446  0.251  0.063
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Click to view the full model residual plots
# --- SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Click to view the results of the ANOVA comparison between reduced and null model.
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      2.2   0.403     none
Reduced model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_size + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## 
##      AIC      BIC   logLik deviance df.resid 
##    -49.8    -22.2     36.9    -73.8       62 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.1   -0.6   -0.2    0.3    3.4 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 3e-02    0.16          
##             day         1e-04    0.01     -1.00
##  Residual               2e-02    0.13          
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error     df t value Pr(>|t|)
## (Intercept)                            0.162      0.038 34.636     4.3    1e-04
## ecosystem_sizeMedium                  -0.002      0.050 35.437     0.0     0.97
## ecosystem_sizeSmall                   -0.052      0.046 37.420    -1.1     0.26
## scale(day)                             0.047      0.024 17.816     1.9     0.07
## scale(water_addition_ml)               0.018      0.034 67.353     0.5     0.60
## scale(baseline)                       -0.014      0.022 20.347    -0.7     0.52
## scale(day):scale(water_addition_ml)   -0.005      0.029 68.460    -0.2     0.85
## scale(day):scale(baseline)            -0.023      0.022 12.772    -1.0     0.32
##                                        
## (Intercept)                         ***
## ecosystem_sizeMedium                   
## ecosystem_sizeSmall                    
## scale(day)                          .  
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecsy_M ecsy_S scl(d) sc(__) scl(b) s():(_
## ecsystm_szM -0.708                                          
## ecsystm_szS -0.678  0.572                                   
## scale(day)   0.188  0.070  0.084                            
## scl(wtr_d_)  0.247  0.046  0.072  0.363                     
## scale(bsln) -0.285  0.409  0.230 -0.020 -0.049              
## scl(d):(__)  0.426 -0.097 -0.065  0.174  0.824 -0.030       
## scl(dy):s() -0.044  0.037  0.036  0.051  0.049  0.350 -0.041
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Click to view the reduced model residual plots
# --- SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Populations

for(eco_type_i in 1:length(ecosystem_type_selected)){
  
  print(ecosystem_type_selected[eco_type_i])

  p = ds_ecosystems %>%
  filter(ecosystem_type == ecosystem_type_selected[eco_type_i]) %>%
  group_by(day) %>%
  summarise(Ble = mean(Ble_indiv_per_ml_dominance, na.rm = TRUE),
            Cep = mean(Cep_indiv_per_ml_dominance, na.rm = TRUE),
            Col = mean(Col_indiv_per_ml_dominance, na.rm = TRUE),
            Eug = mean(Eug_indiv_per_ml_dominance, na.rm = TRUE),
            Eup = mean(Eup_indiv_per_ml_dominance, na.rm = TRUE),
            Lox = mean(Lox_indiv_per_ml_dominance, na.rm = TRUE),
            Pau = mean(Pau_indiv_per_ml_dominance, na.rm = TRUE),
            Pca = mean(Pca_indiv_per_ml_dominance, na.rm = TRUE),
            Spi = mean(Spi_indiv_per_ml_dominance, na.rm = TRUE),
            Spi_te = mean(Spi_te_indiv_per_ml_dominance, na.rm = TRUE),
            Tet = mean(Tet_indiv_per_ml_dominance, na.rm = TRUE)) %>%
    pivot_longer(Ble:Tet, names_to = "species", values_to = "species_indiv_per_ml") %>%
    ggplot(aes(x = day,
               y = species_indiv_per_ml,
               group = interaction(day, species),
               color = species)) +
  geom_point(position = position_dodge(dodging),
             size = treatment_points_size) +
  geom_line(aes(group = species),
            position = position_dodge(dodging),
            linewidth = treatment_lines_linewidth) + 
    labs(x = axis_names %>% 
           filter(variable == "day") %>% 
           pull(axis_name),
         y = axis_names %>% 
           filter(variable == "dominance") %>% 
           pull(axis_name)) +
    coord_cartesian(ylim = c(0, 100))
  
  print(p)

}
## [1] "Small unconnected"

## [1] "Medium unconnected"

## [1] "Large unconnected"

\(S_{L}\) vs \(S\)

ecosystem_type_selected = c("Small connected to large",
                            "Small unconnected")

Shannon

response_variable_selected = "shannon"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value   evidence
## 1     -9.3   0.001 *** strong
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     51.2     73.9    -13.6     27.2       37 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.1   -0.6   -0.1    0.6    2.4 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr
##  culture_ID (Intercept) 1e-05    0.004        
##             day         2e-05    0.005    1.00
##  Residual               9e-02    0.306        
## Number of obs: 49, groups:  culture_ID, 10
## 
## Fixed effects:
##                                            Estimate Std. Error     df t value
## (Intercept)                                   1.378      0.085 12.855    16.3
## ecosystem_typeSmall unconnected              -0.594      0.113 10.479    -5.3
## scale(day)                                   -0.042      0.068 28.406    -0.6
## scale(water_addition_ml)                      0.009      0.069 43.521     0.1
## scale(baseline)                              -0.032      0.054  8.735    -0.6
## ecosystem_typeSmall unconnected:scale(day)   -0.128      0.102 31.487    -1.3
## scale(day):scale(water_addition_ml)          -0.036      0.067 43.804    -0.5
## scale(day):scale(baseline)                   -0.093      0.047 27.159    -2.0
##                                            Pr(>|t|)    
## (Intercept)                                   6e-10 ***
## ecosystem_typeSmall unconnected               3e-04 ***
## scale(day)                                     0.54    
## scale(water_addition_ml)                       0.90    
## scale(baseline)                                0.57    
## ecosystem_typeSmall unconnected:scale(day)     0.22    
## scale(day):scale(water_addition_ml)            0.60    
## scale(day):scale(baseline)                     0.06 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) e_Su:( s():(_
## ecsystm_tSu -0.721                                          
## scale(day)   0.229 -0.173                                   
## scl(wtr_d_)  0.410 -0.315  0.386                            
## scale(bsln)  0.013 -0.023 -0.008 -0.028                     
## ecsys_Su:() -0.245  0.191 -0.682 -0.300  0.025              
## scl(d):(__)  0.441 -0.223  0.265  0.681  0.004 -0.457       
## scl(dy):s() -0.059  0.048 -0.002 -0.052  0.123  0.087 -0.169
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value   evidence
## 1     -9.8   0.001 *** strong
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     50.8     71.6    -14.4     28.8       38 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.15  -0.70   0.01   0.51   2.55 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e-02    0.107         
##             day         5e-05    0.007    -0.76
##  Residual               1e-01    0.311         
## Number of obs: 49, groups:  culture_ID, 10
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             1.35       0.08 11.81    16.5    2e-09
## ecosystem_typeSmall unconnected        -0.57       0.11  9.85    -5.1    5e-04
## scale(day)                             -0.10       0.05 10.39    -1.9     0.08
## scale(water_addition_ml)               -0.02       0.07 41.34    -0.2     0.82
## scale(baseline)                        -0.03       0.05  8.22    -0.6     0.59
## scale(day):scale(water_addition_ml)    -0.07       0.06 44.17    -1.2     0.25
## scale(day):scale(baseline)             -0.09       0.05  8.86    -1.8     0.11
##                                        
## (Intercept)                         ***
## ecosystem_typeSmall unconnected     ***
## scale(day)                          .  
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) s():(_
## ecsystm_tSu -0.709                                   
## scale(day)   0.082 -0.059                            
## scl(wtr_d_)  0.371 -0.282  0.255                     
## scale(bsln)  0.020 -0.027  0.012 -0.022              
## scl(d):(__)  0.390 -0.163 -0.074  0.640  0.018       
## scl(dy):s() -0.041  0.033  0.076 -0.028  0.116 -0.145
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Biomass

response_variable_selected = "bioarea_mm2_per_ml"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value   evidence
## 1     -9.2   0.001 *** strong
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     82.5    105.4    -29.2     58.5       38 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.35  -0.69  -0.04   0.46   2.41 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 0.751    0.87          
##             day         0.001    0.04     -1.00
##  Residual               0.151    0.39          
## Number of obs: 50, groups:  culture_ID, 10
## 
## Fixed effects:
##                                            Estimate Std. Error    df t value
## (Intercept)                                    1.45       0.12 18.13    12.4
## ecosystem_typeSmall unconnected               -0.73       0.16 15.08    -4.5
## scale(day)                                    -0.61       0.13 11.86    -4.6
## scale(water_addition_ml)                       0.26       0.09 39.73     2.9
## scale(baseline)                                0.02       0.08 12.62     0.3
## ecosystem_typeSmall unconnected:scale(day)     0.13       0.20 12.89     0.7
## scale(day):scale(water_addition_ml)            0.02       0.09 43.90     0.2
## scale(day):scale(baseline)                     0.04       0.09 10.40     0.4
##                                            Pr(>|t|)    
## (Intercept)                                   3e-10 ***
## ecosystem_typeSmall unconnected               4e-04 ***
## scale(day)                                    6e-04 ***
## scale(water_addition_ml)                      0.006 ** 
## scale(baseline)                               0.756    
## ecosystem_typeSmall unconnected:scale(day)    0.513    
## scale(day):scale(water_addition_ml)           0.857    
## scale(day):scale(baseline)                    0.705    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) e_Su:( s():(_
## ecsystm_tSu -0.750                                          
## scale(day)  -0.300  0.235                                   
## scl(wtr_d_)  0.404 -0.326  0.271                            
## scale(bsln) -0.290  0.396  0.104 -0.101                     
## ecsys_Su:()  0.152 -0.358 -0.729 -0.220 -0.153              
## scl(d):(__)  0.422 -0.208  0.190  0.642 -0.060 -0.344       
## scl(dy):s()  0.082 -0.157 -0.289 -0.058 -0.473  0.393 -0.096
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value         evidence
## 1    -10.8 < 0.001 **** very strong
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     80.9    101.9    -29.5     58.9       39 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.4   -0.6    0.0    0.5    2.5 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 0.777    0.88          
##             day         0.001    0.04     -1.00
##  Residual               0.152    0.39          
## Number of obs: 50, groups:  culture_ID, 10
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             1.44       0.12 22.43    12.5    1e-11
## ecosystem_typeSmall unconnected        -0.69       0.15 26.87    -4.6    1e-04
## scale(day)                             -0.54       0.09 11.71    -5.9    8e-05
## scale(water_addition_ml)                0.27       0.09 42.66     3.1    0.003
## scale(baseline)                         0.03       0.08 13.84     0.4    0.678
## scale(day):scale(water_addition_ml)     0.04       0.08 49.23     0.4    0.659
## scale(day):scale(baseline)              0.01       0.09 10.01     0.1    0.897
##                                        
## (Intercept)                         ***
## ecosystem_typeSmall unconnected     ***
## scale(day)                          ***
## scale(water_addition_ml)            ** 
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) s():(_
## ecsystm_tSu -0.754                                   
## scale(day)  -0.278 -0.041                            
## scl(wtr_d_)  0.455 -0.445  0.165                     
## scale(bsln) -0.274  0.369 -0.012 -0.140              
## scl(d):(__)  0.512 -0.376 -0.093  0.619 -0.122       
## scl(dy):s()  0.024 -0.018 -0.003  0.031 -0.452  0.045
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Richness

response_variable_selected = "species_richness"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value         evidence
## 1    -11.9 < 0.001 **** very strong
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    181.7    204.7    -78.9    157.7       38 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -1.7   -0.6   -0.2    0.5    2.7 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 0.250    0.50          
##             day         0.001    0.04     -1.00
##  Residual               1.279    1.13          
## Number of obs: 50, groups:  culture_ID, 10
## 
## Fixed effects:
##                                            Estimate Std. Error    df t value
## (Intercept)                                    5.38       0.30 18.09    17.7
## ecosystem_typeSmall unconnected               -2.51       0.42 14.73    -6.0
## scale(day)                                    -0.38       0.28 18.00    -1.4
## scale(water_addition_ml)                       0.39       0.26 46.10     1.5
## scale(baseline)                                0.03       0.20 12.20     0.1
## ecosystem_typeSmall unconnected:scale(day)    -0.32       0.44 21.03    -0.7
## scale(day):scale(water_addition_ml)            0.13       0.25 44.34     0.5
## scale(day):scale(baseline)                    -0.10       0.20 15.37    -0.5
##                                            Pr(>|t|)    
## (Intercept)                                   7e-13 ***
## ecosystem_typeSmall unconnected               3e-05 ***
## scale(day)                                      0.2    
## scale(water_addition_ml)                        0.1    
## scale(baseline)                                 0.9    
## ecosystem_typeSmall unconnected:scale(day)      0.5    
## scale(day):scale(water_addition_ml)             0.6    
## scale(day):scale(baseline)                      0.6    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) e_Su:( s():(_
## ecsystm_tSu -0.753                                          
## scale(day)   0.316 -0.235                                   
## scl(wtr_d_)  0.444 -0.337  0.372                            
## scale(bsln) -0.269  0.405 -0.055 -0.024                     
## ecsys_Su:() -0.305  0.237 -0.740 -0.307  0.046              
## scl(d):(__)  0.451 -0.215  0.300  0.699  0.034 -0.469       
## scl(dy):s() -0.120  0.089 -0.324 -0.082  0.157  0.457 -0.194
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value         evidence
## 1    -13.3 < 0.001 **** very strong
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    180.3    201.3    -79.1    158.3       39 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -1.6   -0.7   -0.2    0.5    2.8 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 0.250    0.50          
##             day         0.001    0.04     -1.00
##  Residual               1.287    1.13          
## Number of obs: 50, groups:  culture_ID, 10
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             5.31       0.29 19.42    18.2    1e-13
## ecosystem_typeSmall unconnected        -2.43       0.41 16.39    -5.9    2e-05
## scale(day)                             -0.53       0.19 17.29    -2.8     0.01
## scale(water_addition_ml)                0.33       0.25 46.93     1.4     0.18
## scale(baseline)                         0.04       0.20 11.95     0.2     0.86
## scale(day):scale(water_addition_ml)     0.05       0.22 47.33     0.2     0.83
## scale(day):scale(baseline)             -0.03       0.18 13.84    -0.2     0.85
##                                        
## (Intercept)                         ***
## ecosystem_typeSmall unconnected     ***
## scale(day)                          *  
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) s():(_
## ecsystm_tSu -0.735                                   
## scale(day)   0.146 -0.091                            
## scl(wtr_d_)  0.382 -0.280  0.225                     
## scale(bsln) -0.267  0.406 -0.030 -0.009              
## scl(d):(__)  0.361 -0.116 -0.079  0.661  0.064       
## scl(dy):s()  0.022 -0.022  0.023  0.069  0.161  0.026
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Evenness

response_variable_selected = "evenness_pielou"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      3.6   0.838     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    -33.9    -11.7     28.9    -57.9       35 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -4.3   -0.5    0.2    0.6    2.2 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e-03    0.038         
##             day         8e-06    0.003    -1.00
##  Residual               2e-02    0.129         
## Number of obs: 47, groups:  culture_ID, 10
## 
## Fixed effects:
##                                            Estimate Std. Error     df t value
## (Intercept)                                   0.794      0.033 20.893    23.9
## ecosystem_typeSmall unconnected               0.014      0.048 16.424     0.3
## scale(day)                                   -0.006      0.031 24.492    -0.2
## scale(water_addition_ml)                     -0.053      0.030 42.197    -1.7
## scale(baseline)                              -0.053      0.023 14.962    -2.3
## ecosystem_typeSmall unconnected:scale(day)   -0.024      0.050 24.777    -0.5
## scale(day):scale(water_addition_ml)          -0.049      0.029 41.381    -1.7
## scale(day):scale(baseline)                   -0.037      0.023 20.514    -1.6
##                                            Pr(>|t|)    
## (Intercept)                                  <2e-16 ***
## ecosystem_typeSmall unconnected                0.77    
## scale(day)                                     0.85    
## scale(water_addition_ml)                       0.09 .  
## scale(baseline)                                0.04 *  
## ecosystem_typeSmall unconnected:scale(day)     0.64    
## scale(day):scale(water_addition_ml)            0.10    
## scale(day):scale(baseline)                     0.12    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) e_Su:( s():(_
## ecsystm_tSu -0.732                                          
## scale(day)   0.191 -0.124                                   
## scl(wtr_d_)  0.423 -0.272  0.366                            
## scale(bsln)  0.291 -0.465 -0.012 -0.075                     
## ecsys_Su:() -0.193  0.122 -0.724 -0.244  0.010              
## scl(d):(__)  0.462 -0.180  0.260  0.699 -0.058 -0.379       
## scl(dy):s()  0.009 -0.009  0.337 -0.013  0.046 -0.471 -0.011
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.9   0.711     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    -35.6    -15.3     28.8    -57.6       36 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -4.2   -0.5    0.2    0.6    2.2 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 2e-03    0.044         
##             day         1e-05    0.003    -1.00
##  Residual               2e-02    0.128         
## Number of obs: 47, groups:  culture_ID, 10
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             0.79       0.03 23.28    24.0   <2e-16
## ecosystem_typeSmall unconnected         0.02       0.05 19.09     0.4     0.71
## scale(day)                             -0.02       0.02 22.88    -0.8     0.45
## scale(water_addition_ml)               -0.06       0.03 43.33    -1.9     0.06
## scale(baseline)                        -0.05       0.02 13.63    -2.3     0.04
## scale(day):scale(water_addition_ml)    -0.05       0.03 45.06    -2.0     0.05
## scale(day):scale(baseline)             -0.04       0.02 20.20    -2.1     0.05
##                                        
## (Intercept)                         ***
## ecosystem_typeSmall unconnected        
## scale(day)                             
## scale(water_addition_ml)            .  
## scale(baseline)                     *  
## scale(day):scale(water_addition_ml) *  
## scale(day):scale(baseline)          .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) s():(_
## ecsystm_tSu -0.725                                   
## scale(day)   0.094 -0.052                            
## scl(wtr_d_)  0.387 -0.241  0.281                     
## scale(bsln)  0.298 -0.471 -0.007 -0.077              
## scl(d):(__)  0.417 -0.133 -0.020  0.678 -0.063       
## scl(dy):s() -0.092  0.051 -0.006 -0.147  0.085 -0.229
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Median Size

response_variable_selected = "median_body_area_µm2"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.1   0.232     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    776.3    799.0   -376.2    752.3       37 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.50  -0.54   0.04   0.49   1.98 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 5e+04    223           
##             day         3e+02     17      -1.00
##  Residual               3e+05    505           
## Number of obs: 49, groups:  culture_ID, 10
## 
## Fixed effects:
##                                            Estimate Std. Error   df t value
## (Intercept)                                    3917        132   22    29.8
## ecosystem_typeSmall unconnected                -301        174   18    -1.7
## scale(day)                                      134        119   16     1.1
## scale(water_addition_ml)                        -19        116   45    -0.2
## scale(baseline)                                   4         83   15     0.1
## ecosystem_typeSmall unconnected:scale(day)       -3        177   19     0.0
## scale(day):scale(water_addition_ml)             -85        110   43    -0.8
## scale(day):scale(baseline)                       19         82   14     0.2
##                                            Pr(>|t|)    
## (Intercept)                                  <2e-16 ***
## ecosystem_typeSmall unconnected                 0.1    
## scale(day)                                      0.3    
## scale(water_addition_ml)                        0.9    
## scale(baseline)                                 1.0    
## ecosystem_typeSmall unconnected:scale(day)      1.0    
## scale(day):scale(water_addition_ml)             0.4    
## scale(day):scale(baseline)                      0.8    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) e_Su:( s():(_
## ecsystm_tSu -0.735                                          
## scale(day)   0.286 -0.221                                   
## scl(wtr_d_)  0.457 -0.364  0.379                            
## scale(bsln) -0.199  0.226 -0.083 -0.165                     
## ecsys_Su:() -0.282  0.245 -0.694 -0.293  0.070              
## scl(d):(__)  0.487 -0.267  0.261  0.691 -0.163 -0.429       
## scl(dy):s() -0.052  0.037 -0.158 -0.103  0.186  0.149 -0.029
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1     -0.9   0.087   * weak
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    774.3    795.1   -376.2    752.3       38 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.50  -0.54   0.04   0.49   1.98 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 5e+04    222           
##             day         3e+02     17      -1.00
##  Residual               3e+05    505           
## Number of obs: 49, groups:  culture_ID, 10
## 
## Fixed effects:
##                                     Estimate Std. Error   df t value Pr(>|t|)
## (Intercept)                             3916        126   25    31.0   <2e-16
## ecosystem_typeSmall unconnected         -300        169   21    -1.8     0.09
## scale(day)                               133         86   17     1.5     0.14
## scale(water_addition_ml)                 -20        111   47    -0.2     0.86
## scale(baseline)                            4         83   15     0.1     0.96
## scale(day):scale(water_addition_ml)      -86         99   47    -0.9     0.39
## scale(day):scale(baseline)                19         81   14     0.2     0.82
##                                        
## (Intercept)                         ***
## ecosystem_typeSmall unconnected     .  
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) s():(_
## ecsystm_tSu -0.716                                   
## scale(day)   0.130 -0.073                            
## scl(wtr_d_)  0.408 -0.315  0.255                     
## scale(bsln) -0.187  0.216 -0.049 -0.152              
## scl(d):(__)  0.422 -0.185 -0.056  0.654 -0.148       
## scl(dy):s() -0.011  0.000 -0.077 -0.063  0.177  0.039
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Populations

for(eco_type_i in 1:length(ecosystem_type_selected)){
  
  print(ecosystem_type_selected[eco_type_i])

  p = ds_ecosystems %>%
  filter(ecosystem_type == ecosystem_type_selected[eco_type_i]) %>%
  group_by(day) %>%
  summarise(Ble = mean(Ble_indiv_per_ml_dominance, na.rm = TRUE),
            Cep = mean(Cep_indiv_per_ml_dominance, na.rm = TRUE),
            Col = mean(Col_indiv_per_ml_dominance, na.rm = TRUE),
            Eug = mean(Eug_indiv_per_ml_dominance, na.rm = TRUE),
            Eup = mean(Eup_indiv_per_ml_dominance, na.rm = TRUE),
            Lox = mean(Lox_indiv_per_ml_dominance, na.rm = TRUE),
            Pau = mean(Pau_indiv_per_ml_dominance, na.rm = TRUE),
            Pca = mean(Pca_indiv_per_ml_dominance, na.rm = TRUE),
            Spi = mean(Spi_indiv_per_ml_dominance, na.rm = TRUE),
            Spi_te = mean(Spi_te_indiv_per_ml_dominance, na.rm = TRUE),
            Tet = mean(Tet_indiv_per_ml_dominance, na.rm = TRUE)) %>%
    pivot_longer(Ble:Tet, names_to = "species", values_to = "species_indiv_per_ml") %>%
    ggplot(aes(x = day,
               y = species_indiv_per_ml,
               group = interaction(day, species),
               color = species)) +
  geom_point(position = position_dodge(dodging),
             size = treatment_points_size) +
  geom_line(aes(group = species),
            position = position_dodge(dodging),
            linewidth = treatment_lines_linewidth) + 
    labs(x = axis_names %>% 
           filter(variable == "day") %>% 
           pull(axis_name),
         y = axis_names %>% 
           filter(variable == "dominance") %>% 
           pull(axis_name)) +
    coord_cartesian(ylim = c(0, 100))
  
  print(p)

}
## [1] "Small connected to large"

## [1] "Small unconnected"

Evaporation

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       "water_addition_ml")

\(S_{L}\) vs \(S_{S}\)

ecosystem_type_selected = c("Small connected to large",
                     "Small connected to small")

Shannon

response_variable_selected = "shannon"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value         evidence
## 1    -18.3 < 0.001 **** very strong
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     68.4     96.0    -22.2     44.4       62 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.82  -0.45   0.01   0.45   2.00 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e-12    1e-06         
##             day         5e-15    7e-08    -1.00
##  Residual               1e-01    3e-01         
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                                   Estimate Std. Error    df
## (Intercept)                                           1.39       0.07 74.00
## ecosystem_typeSmall connected to small               -0.57       0.09 74.00
## scale(day)                                           -0.04       0.07 74.00
## scale(water_addition_ml)                             -0.05       0.05 74.00
## scale(baseline)                                       0.05       0.04 74.00
## ecosystem_typeSmall connected to small:scale(day)    -0.21       0.09 74.00
## scale(day):scale(water_addition_ml)                  -0.05       0.05 74.00
## scale(day):scale(baseline)                            0.02       0.04 74.00
##                                                   t value Pr(>|t|)    
## (Intercept)                                          19.4   <2e-16 ***
## ecosystem_typeSmall connected to small               -6.5    9e-09 ***
## scale(day)                                           -0.6     0.57    
## scale(water_addition_ml)                             -1.0     0.34    
## scale(baseline)                                       1.1     0.28    
## ecosystem_typeSmall connected to small:scale(day)    -2.3     0.02 *  
## scale(day):scale(water_addition_ml)                  -1.0     0.30    
## scale(day):scale(baseline)                            0.4     0.70    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ec_Scts scl(d) sc(__) scl(b) e_Scts: s():(_
## ecsyst_Scts -0.783                                            
## scale(day)   0.003 -0.009                                     
## scl(wtr_d_)  0.165 -0.032   0.166                             
## scale(bsln)  0.298 -0.419   0.013  0.018                      
## ecs_Scts:()  0.007 -0.020  -0.792  0.103  0.019               
## scl(d):(__)  0.240  0.110  -0.004  0.421 -0.136 -0.039        
## scl(dy):s()  0.000  0.023   0.301 -0.114 -0.030 -0.419   0.060
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value         evidence
## 1    -15.2 < 0.001 **** very strong
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     71.5     96.8    -24.7     49.5       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.67  -0.52   0.05   0.65   1.85 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 7e-10    3e-05         
##             day         3e-12    2e-06    -1.00
##  Residual               1e-01    3e-01         
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                        Estimate Std. Error    df t value
## (Intercept)                                1.39       0.07 74.00    18.8
## ecosystem_typeSmall connected to small    -0.58       0.09 74.00    -6.3
## scale(day)                                -0.17       0.05 74.00    -3.8
## scale(water_addition_ml)                  -0.03       0.05 74.00    -0.7
## scale(baseline)                            0.05       0.04 74.00     1.1
## scale(day):scale(water_addition_ml)       -0.06       0.05 74.00    -1.1
## scale(day):scale(baseline)                -0.02       0.04 74.00    -0.6
##                                        Pr(>|t|)    
## (Intercept)                              <2e-16 ***
## ecosystem_typeSmall connected to small    2e-08 ***
## scale(day)                                3e-04 ***
## scale(water_addition_ml)                    0.5    
## scale(baseline)                             0.3    
## scale(day):scale(water_addition_ml)         0.3    
## scale(day):scale(baseline)                  0.5    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) e_Scts scl(d) sc(__) scl(b) s():(_
## ecsyst_Scts -0.783                                   
## scale(day)   0.015 -0.041                            
## scl(wtr_d_)  0.165 -0.030  0.408                     
## scale(bsln)  0.298 -0.419  0.046  0.016              
## scl(d):(__)  0.240  0.109 -0.057  0.428 -0.136       
## scl(dy):s()  0.004  0.016 -0.056 -0.079 -0.024  0.048
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Biomass

response_variable_selected = "bioarea_mm2_per_ml"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value   evidence
## 1     -7.6   0.003 *** strong
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    104.3    132.0    -40.2     80.3       62 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -1.83  -0.51   0.03   0.37   2.79 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 3e-01    0.59          
##             day         5e-04    0.02     -1.00
##  Residual               1e-01    0.38          
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                                   Estimate Std. Error    df
## (Intercept)                                           1.26       0.11 21.34
## ecosystem_typeSmall connected to small               -0.52       0.14 19.11
## scale(day)                                           -0.60       0.11 21.37
## scale(water_addition_ml)                              0.04       0.06 61.41
## scale(baseline)                                      -0.09       0.07 19.13
## ecosystem_typeSmall connected to small:scale(day)     0.05       0.14 20.04
## scale(day):scale(water_addition_ml)                  -0.22       0.06 67.18
## scale(day):scale(baseline)                            0.05       0.07 20.48
##                                                   t value Pr(>|t|)    
## (Intercept)                                          11.2    2e-10 ***
## ecosystem_typeSmall connected to small               -3.8    0.001 ** 
## scale(day)                                           -5.5    2e-05 ***
## scale(water_addition_ml)                              0.8    0.448    
## scale(baseline)                                      -1.4    0.177    
## ecosystem_typeSmall connected to small:scale(day)     0.4    0.696    
## scale(day):scale(water_addition_ml)                  -3.4    0.001 ** 
## scale(day):scale(baseline)                            0.8    0.450    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ec_Scts scl(d) sc(__) scl(b) e_Scts: s():(_
## ecsyst_Scts -0.819                                            
## scale(day)  -0.344  0.303                                     
## scl(wtr_d_)  0.134 -0.042   0.207                             
## scale(bsln)  0.424 -0.490  -0.149  0.042                      
## ecs_Scts:()  0.289 -0.373  -0.824 -0.009  0.174               
## scl(d):(__)  0.260  0.009   0.020  0.376  0.077 -0.081        
## scl(dy):s() -0.114  0.177   0.421  0.109 -0.360 -0.493   0.131
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value   evidence
## 1     -9.5   0.001 *** strong
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    102.5    127.8    -40.2     80.5       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -1.85  -0.50   0.04   0.37   2.84 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 4e-01    0.60          
##             day         5e-04    0.02     -1.00
##  Residual               1e-01    0.38          
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                        Estimate Std. Error    df t value
## (Intercept)                                1.24       0.11 30.31    11.5
## ecosystem_typeSmall connected to small    -0.50       0.13 30.22    -3.9
## scale(day)                                -0.56       0.06 26.35    -9.0
## scale(water_addition_ml)                   0.05       0.06 61.33     0.8
## scale(baseline)                           -0.10       0.07 21.57    -1.5
## scale(day):scale(water_addition_ml)       -0.21       0.06 67.17    -3.3
## scale(day):scale(baseline)                 0.06       0.06 20.19     1.1
##                                        Pr(>|t|)    
## (Intercept)                               1e-12 ***
## ecosystem_typeSmall connected to small    5e-04 ***
## scale(day)                                2e-09 ***
## scale(water_addition_ml)                  0.445    
## scale(baseline)                           0.150    
## scale(day):scale(water_addition_ml)       0.001 ** 
## scale(day):scale(baseline)                0.282    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) e_Scts scl(d) sc(__) scl(b) s():(_
## ecsyst_Scts -0.800                                   
## scale(day)  -0.197 -0.009                            
## scl(wtr_d_)  0.143 -0.048  0.353                     
## scale(bsln)  0.396 -0.465 -0.009  0.044              
## scl(d):(__)  0.297 -0.024 -0.084  0.376  0.094       
## scl(dy):s()  0.034 -0.008  0.029  0.120 -0.322  0.105
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Richness

response_variable_selected = "species_richness"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value         evidence
## 1    -25.2 < 0.001 **** very strong
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    238.9    266.6   -107.5    214.9       62 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.63  -0.65  -0.06   0.44   3.07 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr
##  culture_ID (Intercept) 0e+00    0e+00        
##             day         2e-15    4e-08     NaN
##  Residual               1e+00    1e+00        
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                                   Estimate Std. Error    df
## (Intercept)                                           5.19       0.22 74.00
## ecosystem_typeSmall connected to small               -2.06       0.26 74.00
## scale(day)                                           -0.53       0.22 74.00
## scale(water_addition_ml)                              0.01       0.15 74.00
## scale(baseline)                                       0.22       0.12 74.00
## ecosystem_typeSmall connected to small:scale(day)    -0.33       0.26 74.00
## scale(day):scale(water_addition_ml)                  -0.20       0.16 74.00
## scale(day):scale(baseline)                           -0.02       0.12 74.00
##                                                   t value Pr(>|t|)    
## (Intercept)                                          23.9   <2e-16 ***
## ecosystem_typeSmall connected to small               -8.1    1e-11 ***
## scale(day)                                           -2.5     0.02 *  
## scale(water_addition_ml)                              0.1     0.94    
## scale(baseline)                                       1.8     0.07 .  
## ecosystem_typeSmall connected to small:scale(day)    -1.3     0.20    
## scale(day):scale(water_addition_ml)                  -1.3     0.21    
## scale(day):scale(baseline)                           -0.2     0.87    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ec_Scts scl(d) sc(__) scl(b) e_Scts: s():(_
## ecsyst_Scts -0.759                                            
## scale(day)  -0.004 -0.008                                     
## scl(wtr_d_)  0.171 -0.025   0.208                             
## scale(bsln)  0.022 -0.055   0.008 -0.003                      
## ecs_Scts:()  0.008 -0.010  -0.769  0.066  0.001               
## scl(d):(__)  0.295  0.062  -0.022  0.440 -0.062 -0.011        
## scl(dy):s() -0.024 -0.002   0.025 -0.090 -0.006 -0.053  -0.068
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value         evidence
## 1    -25.5 < 0.001 **** very strong
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    238.6    263.9   -108.3    216.6       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.55  -0.68  -0.08   0.58   3.05 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e-14    1e-07         
##             day         2e-17    5e-09    -1.00
##  Residual               1e+00    1e+00         
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                        Estimate Std. Error    df t value
## (Intercept)                                5.19       0.22 74.00    23.7
## ecosystem_typeSmall connected to small    -2.06       0.26 74.00    -8.0
## scale(day)                                -0.74       0.14 74.00    -5.3
## scale(water_addition_ml)                   0.03       0.16 74.00     0.2
## scale(baseline)                            0.22       0.12 74.00     1.8
## scale(day):scale(water_addition_ml)       -0.20       0.16 74.00    -1.3
## scale(day):scale(baseline)                -0.03       0.12 74.00    -0.2
##                                        Pr(>|t|)    
## (Intercept)                              <2e-16 ***
## ecosystem_typeSmall connected to small    1e-11 ***
## scale(day)                                1e-06 ***
## scale(water_addition_ml)                   0.87    
## scale(baseline)                            0.08 .  
## scale(day):scale(water_addition_ml)        0.21    
## scale(day):scale(baseline)                 0.81    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) e_Scts scl(d) sc(__) scl(b) s():(_
## ecsyst_Scts -0.759                                   
## scale(day)   0.003 -0.024                            
## scl(wtr_d_)  0.171 -0.025  0.405                     
## scale(bsln)  0.022 -0.055  0.013 -0.003              
## scl(d):(__)  0.295  0.061 -0.048  0.442 -0.062       
## scl(dy):s() -0.023 -0.002 -0.025 -0.087 -0.006 -0.069
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Evenness

response_variable_selected = "evenness_pielou"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      2.8   0.537     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    -80.9    -54.3     52.5   -104.9       56 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.7   -0.6    0.3    0.6    2.0 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 2e-16    1e-08         
##             day         3e-19    5e-10    -1.00
##  Residual               1e-02    1e-01         
## Number of obs: 68, groups:  culture_ID, 15
## 
## Fixed effects:
##                                                   Estimate Std. Error     df
## (Intercept)                                          8e-01      3e-02  7e+01
## ecosystem_typeSmall connected to small              -5e-03      3e-02  7e+01
## scale(day)                                           3e-02      3e-02  7e+01
## scale(water_addition_ml)                            -3e-02      2e-02  7e+01
## scale(baseline)                                     -2e-02      2e-02  7e+01
## ecosystem_typeSmall connected to small:scale(day)   -4e-02      3e-02  7e+01
## scale(day):scale(water_addition_ml)                 -7e-04      2e-02  7e+01
## scale(day):scale(baseline)                           2e-02      2e-02  7e+01
##                                                   t value Pr(>|t|)    
## (Intercept)                                          32.7   <2e-16 ***
## ecosystem_typeSmall connected to small               -0.2     0.88    
## scale(day)                                            1.2     0.25    
## scale(water_addition_ml)                             -2.0     0.05 *  
## scale(baseline)                                      -1.2     0.22    
## ecosystem_typeSmall connected to small:scale(day)    -1.1     0.27    
## scale(day):scale(water_addition_ml)                   0.0     0.97    
## scale(day):scale(baseline)                            1.1     0.29    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ec_Scts scl(d) sc(__) scl(b) e_Scts: s():(_
## ecsyst_Scts -0.781                                            
## scale(day)  -0.023  0.026                                     
## scl(wtr_d_)  0.160 -0.041   0.200                             
## scale(bsln)  0.380 -0.505   0.006  0.041                      
## ecs_Scts:()  0.020 -0.034  -0.782  0.087  0.017               
## scl(d):(__)  0.250  0.096   0.057  0.375 -0.091 -0.103        
## scl(dy):s()  0.031  0.023   0.375 -0.045 -0.037 -0.510   0.175
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1        2   0.848     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    -81.7    -57.3     51.9   -103.7       57 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.6   -0.6    0.3    0.6    1.8 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 8e-10    3e-05         
##             day         2e-12    1e-06    -1.00
##  Residual               1e-02    1e-01         
## Number of obs: 68, groups:  culture_ID, 15
## 
## Fixed effects:
##                                        Estimate Std. Error     df t value
## (Intercept)                               0.834      0.026 68.000    32.4
## ecosystem_typeSmall connected to small   -0.006      0.033 68.000    -0.2
## scale(day)                                0.008      0.016 68.000     0.5
## scale(water_addition_ml)                 -0.033      0.017 68.000    -1.9
## scale(baseline)                          -0.019      0.016 68.000    -1.2
## scale(day):scale(water_addition_ml)      -0.003      0.018 68.000    -0.2
## scale(day):scale(baseline)                0.008      0.014 68.000     0.6
##                                        Pr(>|t|)    
## (Intercept)                              <2e-16 ***
## ecosystem_typeSmall connected to small     0.85    
## scale(day)                                 0.63    
## scale(water_addition_ml)                   0.06 .  
## scale(baseline)                            0.23    
## scale(day):scale(water_addition_ml)        0.88    
## scale(day):scale(baseline)                 0.56    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) e_Scts scl(d) sc(__) scl(b) s():(_
## ecsyst_Scts -0.781                                   
## scale(day)  -0.012 -0.001                            
## scl(wtr_d_)  0.158 -0.039  0.432                     
## scale(bsln)  0.380 -0.505  0.030  0.039              
## scl(d):(__)  0.253  0.093 -0.038  0.387 -0.090       
## scl(dy):s()  0.047  0.007 -0.045 -0.001 -0.033  0.143
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Median Size

response_variable_selected = "median_body_area_µm2"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      2.6   0.492     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1173.1   1200.7   -574.5   1149.1       62 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.9   -0.7    0.1    0.7    2.1 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 2e+05    391           
##             day         5e+02     23      -1.00
##  Residual               3e+05    552           
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                                   Estimate Std. Error   df
## (Intercept)                                           3923        120   40
## ecosystem_typeSmall connected to small                -149        142   36
## scale(day)                                             191        129   19
## scale(water_addition_ml)                                62         84   67
## scale(baseline)                                        -43         68   37
## ecosystem_typeSmall connected to small:scale(day)       70        155   18
## scale(day):scale(water_addition_ml)                   -104         89   70
## scale(day):scale(baseline)                            -128         74   19
##                                                   t value Pr(>|t|)    
## (Intercept)                                          32.6   <2e-16 ***
## ecosystem_typeSmall connected to small               -1.1      0.3    
## scale(day)                                            1.5      0.2    
## scale(water_addition_ml)                              0.7      0.5    
## scale(baseline)                                      -0.6      0.5    
## ecosystem_typeSmall connected to small:scale(day)     0.4      0.7    
## scale(day):scale(water_addition_ml)                  -1.2      0.2    
## scale(day):scale(baseline)                           -1.7      0.1    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ec_Scts scl(d) sc(__) scl(b) e_Scts: s():(_
## ecsyst_Scts -0.758                                            
## scale(day)   0.115 -0.107                                     
## scl(wtr_d_)  0.180 -0.024   0.189                             
## scale(bsln) -0.036  0.008  -0.025 -0.144                      
## ecs_Scts:() -0.093  0.116  -0.778  0.053 -0.012               
## scl(d):(__)  0.302  0.057  -0.014  0.466 -0.086 -0.015        
## scl(dy):s() -0.053 -0.014  -0.007 -0.097  0.145  0.015  -0.172
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      0.8    0.27     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1171.3   1196.6   -574.6   1149.3       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.8   -0.7    0.1    0.7    2.1 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 2e+05    402           
##             day         6e+02     24      -1.00
##  Residual               3e+05    553           
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                        Estimate Std. Error   df t value
## (Intercept)                                3928        120   44    32.7
## ecosystem_typeSmall connected to small     -156        140   43    -1.1
## scale(day)                                  236         82   25     2.9
## scale(water_addition_ml)                     60         84   67     0.7
## scale(baseline)                             -43         68   37    -0.6
## scale(day):scale(water_addition_ml)        -103         89   70    -1.2
## scale(day):scale(baseline)                 -129         75   19    -1.7
##                                        Pr(>|t|)    
## (Intercept)                              <2e-16 ***
## ecosystem_typeSmall connected to small    0.273    
## scale(day)                                0.008 ** 
## scale(water_addition_ml)                  0.482    
## scale(baseline)                           0.531    
## scale(day):scale(water_addition_ml)       0.252    
## scale(day):scale(baseline)                0.102    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) e_Scts scl(d) sc(__) scl(b) s():(_
## ecsyst_Scts -0.755                                   
## scale(day)   0.069 -0.026                            
## scl(wtr_d_)  0.186 -0.030  0.364                     
## scale(bsln) -0.037  0.010 -0.055 -0.143              
## scl(d):(__)  0.302  0.059 -0.041  0.467 -0.086       
## scl(dy):s() -0.052 -0.016  0.007 -0.098  0.147 -0.171
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Populations

for(eco_type_i in 1:length(ecosystem_type_selected)){
  
  print(ecosystem_type_selected[eco_type_i])

  p = ds_ecosystems %>%
  filter(ecosystem_type == ecosystem_type_selected[eco_type_i]) %>%
  group_by(day) %>%
  summarise(Ble = mean(Ble_indiv_per_ml_dominance, na.rm = TRUE),
            Cep = mean(Cep_indiv_per_ml_dominance, na.rm = TRUE),
            Col = mean(Col_indiv_per_ml_dominance, na.rm = TRUE),
            Eug = mean(Eug_indiv_per_ml_dominance, na.rm = TRUE),
            Eup = mean(Eup_indiv_per_ml_dominance, na.rm = TRUE),
            Lox = mean(Lox_indiv_per_ml_dominance, na.rm = TRUE),
            Pau = mean(Pau_indiv_per_ml_dominance, na.rm = TRUE),
            Pca = mean(Pca_indiv_per_ml_dominance, na.rm = TRUE),
            Spi = mean(Spi_indiv_per_ml_dominance, na.rm = TRUE),
            Spi_te = mean(Spi_te_indiv_per_ml_dominance, na.rm = TRUE),
            Tet = mean(Tet_indiv_per_ml_dominance, na.rm = TRUE)) %>%
    pivot_longer(Ble:Tet, names_to = "species", values_to = "species_indiv_per_ml") %>%
    ggplot(aes(x = day,
               y = species_indiv_per_ml,
               group = interaction(day, species),
               color = species)) +
  geom_point(position = position_dodge(dodging),
             size = treatment_points_size) +
  geom_line(aes(group = species),
            position = position_dodge(dodging),
            linewidth = treatment_lines_linewidth) + 
    labs(x = axis_names %>% 
           filter(variable == "day") %>% 
           pull(axis_name),
         y = axis_names %>% 
           filter(variable == "dominance") %>% 
           pull(axis_name)) +
    coord_cartesian(ylim = c(0, 100))
  
  print(p)

}
## [1] "Small connected to large"

## [1] "Small connected to small"

Evaporation

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       "water_addition_ml")

\(S_{S}\) vs \(S\)

ecosystem_type_selected = c("Small connected to small",
                     "Small unconnected")

Shannon

response_variable_selected = "shannon"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1        3   0.618     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     90.7    118.2    -33.4     66.7       61 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.78  -0.50   0.06   0.66   2.15 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 2e-02    0.12          
##             day         1e-04    0.01     -1.00
##  Residual               1e-01    0.37          
## Number of obs: 73, groups:  culture_ID, 15
## 
## Fixed effects:
##                                            Estimate Std. Error    df t value
## (Intercept)                                    0.81       0.07 29.05    11.8
## ecosystem_typeSmall unconnected               -0.04       0.11 21.49    -0.4
## scale(day)                                    -0.23       0.06 36.57    -3.6
## scale(water_addition_ml)                      -0.02       0.06 70.04    -0.4
## scale(baseline)                               -0.01       0.05 18.77    -0.3
## ecosystem_typeSmall unconnected:scale(day)     0.09       0.12 34.32     0.8
## scale(day):scale(water_addition_ml)           -0.11       0.06 66.90    -1.8
## scale(day):scale(baseline)                    -0.01       0.05 29.11    -0.3
##                                            Pr(>|t|)    
## (Intercept)                                   1e-12 ***
## ecosystem_typeSmall unconnected                0.72    
## scale(day)                                    9e-04 ***
## scale(water_addition_ml)                       0.71    
## scale(baseline)                                0.80    
## ecosystem_typeSmall unconnected:scale(day)     0.42    
## scale(day):scale(water_addition_ml)            0.07 .  
## scale(day):scale(baseline)                     0.79    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) e_Su:( s():(_
## ecsystm_tSu -0.610                                          
## scale(day)   0.199 -0.155                                   
## scl(wtr_d_)  0.300 -0.210  0.407                            
## scale(bsln) -0.209  0.376 -0.012  0.040                     
## ecsys_Su:() -0.228  0.217 -0.575 -0.201  0.071              
## scl(d):(__)  0.474 -0.170  0.138  0.486 -0.010 -0.332       
## scl(dy):s() -0.027  0.075 -0.223 -0.010  0.131  0.383  0.007
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.7   0.573     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     89.4    114.6    -33.7     67.4       62 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.71  -0.51   0.08   0.64   2.06 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 2e-02    0.14          
##             day         1e-04    0.01     -1.00
##  Residual               1e-01    0.37          
## Number of obs: 73, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             0.82       0.07 31.64    12.2    2e-13
## ecosystem_typeSmall unconnected        -0.06       0.11 26.05    -0.6      0.6
## scale(day)                             -0.20       0.05 35.14    -3.8    6e-04
## scale(water_addition_ml)               -0.01       0.06 70.77    -0.2      0.8
## scale(baseline)                        -0.02       0.05 19.20    -0.3      0.8
## scale(day):scale(water_addition_ml)    -0.09       0.06 65.88    -1.6      0.1
## scale(day):scale(baseline)             -0.03       0.05 26.81    -0.6      0.5
##                                        
## (Intercept)                         ***
## ecosystem_typeSmall unconnected        
## scale(day)                          ***
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) s():(_
## ecsystm_tSu -0.587                                   
## scale(day)   0.099 -0.038                            
## scl(wtr_d_)  0.265 -0.170  0.360                     
## scale(bsln) -0.197  0.370  0.036  0.057              
## scl(d):(__)  0.429 -0.100 -0.067  0.457  0.017       
## scl(dy):s()  0.067 -0.008 -0.004  0.075  0.132  0.153
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Biomass

response_variable_selected = "bioarea_mm2_per_ml"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      0.7   0.189     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    110.3    138.0    -43.2     86.3       62 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.90  -0.63  -0.04   0.48   2.98 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 9e-02    0.29          
##             day         1e-04    0.01     -1.00
##  Residual               2e-01    0.43          
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                            Estimate Std. Error    df t value
## (Intercept)                                    0.77       0.08 47.78      10
## ecosystem_typeSmall unconnected               -0.17       0.14 37.96      -1
## scale(day)                                    -0.58       0.08 34.76      -8
## scale(water_addition_ml)                       0.08       0.07 62.15       1
## scale(baseline)                               -0.10       0.07 36.31      -2
## ecosystem_typeSmall unconnected:scale(day)     0.23       0.14 29.72       2
## scale(day):scale(water_addition_ml)           -0.20       0.07 72.81      -3
## scale(day):scale(baseline)                     0.07       0.07 30.54       1
##                                            Pr(>|t|)    
## (Intercept)                                   5e-13 ***
## ecosystem_typeSmall unconnected               0.243    
## scale(day)                                    6e-09 ***
## scale(water_addition_ml)                      0.237    
## scale(baseline)                               0.129    
## ecosystem_typeSmall unconnected:scale(day)    0.121    
## scale(day):scale(water_addition_ml)           0.006 ** 
## scale(day):scale(baseline)                    0.320    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) e_Su:( s():(_
## ecsystm_tSu -0.647                                          
## scale(day)  -0.023 -0.003                                   
## scl(wtr_d_)  0.300 -0.181  0.332                            
## scale(bsln) -0.327  0.587  0.047  0.066                     
## ecsys_Su:() -0.032 -0.069 -0.630 -0.109 -0.070              
## scl(d):(__)  0.461 -0.115  0.038  0.486  0.068 -0.172       
## scl(dy):s()  0.139 -0.087 -0.347  0.146 -0.081  0.544  0.230
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.1   0.342     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    110.8    136.1    -44.4     88.8       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -3.07  -0.55  -0.03   0.47   2.53 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e-01    0.38          
##             day         2e-04    0.02     -1.00
##  Residual               2e-01    0.43          
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error     df t value Pr(>|t|)
## (Intercept)                            0.773      0.080 46.659     9.6    1e-12
## ecosystem_typeSmall unconnected       -0.144      0.142 44.153    -1.0     0.32
## scale(day)                            -0.504      0.061 29.000    -8.2    5e-09
## scale(water_addition_ml)               0.092      0.067 61.941     1.4     0.17
## scale(baseline)                       -0.093      0.067 39.258    -1.4     0.17
## scale(day):scale(water_addition_ml)   -0.181      0.071 72.541    -2.6     0.01
## scale(day):scale(baseline)             0.009      0.061 26.975     0.2     0.88
##                                        
## (Intercept)                         ***
## ecosystem_typeSmall unconnected        
## scale(day)                          ***
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml) *  
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) s():(_
## ecsystm_tSu -0.651                                   
## scale(day)  -0.082 -0.058                            
## scl(wtr_d_)  0.297 -0.193  0.331                     
## scale(bsln) -0.329  0.584  0.004  0.056              
## scl(d):(__)  0.466 -0.133 -0.096  0.471  0.053       
## scl(dy):s()  0.182 -0.060 -0.008  0.238 -0.082  0.382
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Richness

response_variable_selected = "species_richness"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      2.8   0.538     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    262.6    290.2   -119.3    238.6       62 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.54  -0.60  -0.05   0.50   2.78 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 4e-03    0.07          
##             day         4e-04    0.02     -1.00
##  Residual               1e+00    1.17          
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                            Estimate Std. Error    df t value
## (Intercept)                                    3.11       0.23 23.39    13.5
## ecosystem_typeSmall unconnected               -0.36       0.41 16.94    -0.9
## scale(day)                                    -0.82       0.20 49.33    -4.1
## scale(water_addition_ml)                       0.03       0.18 68.70     0.2
## scale(baseline)                               -0.06       0.19 16.11    -0.3
## ecosystem_typeSmall unconnected:scale(day)     0.22       0.38 47.24     0.6
## scale(day):scale(water_addition_ml)           -0.33       0.19 66.24    -1.7
## scale(day):scale(baseline)                    -0.14       0.17 43.97    -0.8
##                                            Pr(>|t|)    
## (Intercept)                                   2e-12 ***
## ecosystem_typeSmall unconnected                0.40    
## scale(day)                                    2e-04 ***
## scale(water_addition_ml)                       0.87    
## scale(baseline)                                0.75    
## ecosystem_typeSmall unconnected:scale(day)     0.56    
## scale(day):scale(water_addition_ml)            0.09 .  
## scale(day):scale(baseline)                     0.41    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) e_Su:( s():(_
## ecsystm_tSu -0.635                                          
## scale(day)   0.187 -0.130                                   
## scl(wtr_d_)  0.281 -0.171  0.398                            
## scale(bsln) -0.291  0.536 -0.010  0.068                     
## ecsys_Su:() -0.208  0.130 -0.623 -0.194  0.021              
## scl(d):(__)  0.420 -0.102  0.162  0.497  0.083 -0.352       
## scl(dy):s() -0.057  0.052 -0.320  0.021  0.091  0.543 -0.067
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.1   0.343     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    260.9    286.2   -119.4    238.9       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.47  -0.59  -0.09   0.55   2.73 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e-02    0.10          
##             day         4e-04    0.02     -1.00
##  Residual               1e+00    1.18          
## Number of obs: 74, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             3.14       0.23 24.56    13.9    4e-13
## ecosystem_typeSmall unconnected        -0.39       0.41 18.42    -1.0      0.3
## scale(day)                             -0.75       0.16 50.74    -4.7    2e-05
## scale(water_addition_ml)                0.05       0.18 68.82     0.3      0.8
## scale(baseline)                        -0.07       0.19 16.54    -0.3      0.7
## scale(day):scale(water_addition_ml)    -0.29       0.18 65.18    -1.6      0.1
## scale(day):scale(baseline)             -0.20       0.14 42.55    -1.4      0.2
##                                        
## (Intercept)                         ***
## ecosystem_typeSmall unconnected        
## scale(day)                          ***
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) s():(_
## ecsystm_tSu -0.626                                   
## scale(day)   0.077 -0.063                            
## scl(wtr_d_)  0.252 -0.151  0.361                     
## scale(bsln) -0.292  0.538  0.004  0.075              
## scl(d):(__)  0.381 -0.060 -0.078  0.468  0.098       
## scl(dy):s()  0.068 -0.022  0.028  0.153  0.098  0.158
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Evenness

response_variable_selected = "evenness_pielou"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.9   0.352     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    -37.4    -11.3     30.7    -61.4       53 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -4.4   -0.6    0.2    0.7    1.6 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 7e-04    0.027         
##             day         3e-06    0.002    -1.00
##  Residual               2e-02    0.150         
## Number of obs: 65, groups:  culture_ID, 15
## 
## Fixed effects:
##                                            Estimate Std. Error     df t value
## (Intercept)                                   0.807      0.027 57.952    29.8
## ecosystem_typeSmall unconnected              -0.030      0.042 52.301    -0.7
## scale(day)                                    0.005      0.026 36.971     0.2
## scale(water_addition_ml)                     -0.028      0.024 63.221    -1.1
## scale(baseline)                              -0.029      0.019 53.611    -1.5
## ecosystem_typeSmall unconnected:scale(day)   -0.060      0.043 30.680    -1.4
## scale(day):scale(water_addition_ml)          -0.027      0.025 64.583    -1.1
## scale(day):scale(baseline)                    0.001      0.019 28.685     0.1
##                                            Pr(>|t|)    
## (Intercept)                                  <2e-16 ***
## ecosystem_typeSmall unconnected                 0.5    
## scale(day)                                      0.8    
## scale(water_addition_ml)                        0.3    
## scale(baseline)                                 0.1    
## ecosystem_typeSmall unconnected:scale(day)      0.2    
## scale(day):scale(water_addition_ml)             0.3    
## scale(day):scale(baseline)                      0.9    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) e_Su:( s():(_
## ecsystm_tSu -0.587                                          
## scale(day)   0.137 -0.120                                   
## scl(wtr_d_)  0.313 -0.247  0.445                            
## scale(bsln) -0.108  0.187 -0.004  0.013                     
## ecsys_Su:() -0.186  0.081 -0.576 -0.196  0.018              
## scl(d):(__)  0.502 -0.152  0.154  0.432 -0.026 -0.336       
## scl(dy):s()  0.042  0.002 -0.115  0.011 -0.036  0.142  0.113
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.7   0.611     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    -37.6    -13.6     29.8    -59.6       54 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -4.5   -0.5    0.2    0.5    1.8 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 4e-03    0.061         
##             day         2e-05    0.004    -1.00
##  Residual               2e-02    0.151         
## Number of obs: 65, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error     df t value Pr(>|t|)
## (Intercept)                            0.800      0.027 55.424    29.6   <2e-16
## ecosystem_typeSmall unconnected       -0.022      0.042 49.745    -0.5      0.6
## scale(day)                            -0.016      0.022 29.952    -0.7      0.5
## scale(water_addition_ml)              -0.034      0.024 63.308    -1.4      0.2
## scale(baseline)                       -0.028      0.020 42.881    -1.4      0.2
## scale(day):scale(water_addition_ml)   -0.038      0.024 62.021    -1.6      0.1
## scale(day):scale(baseline)             0.006      0.020 23.247     0.3      0.8
##                                        
## (Intercept)                         ***
## ecosystem_typeSmall unconnected        
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) s():(_
## ecsystm_tSu -0.577                                   
## scale(day)   0.070 -0.083                            
## scl(wtr_d_)  0.287 -0.224  0.405                     
## scale(bsln) -0.104  0.184  0.009  0.018              
## scl(d):(__)  0.467 -0.117 -0.049  0.406 -0.018       
## scl(dy):s()  0.068 -0.009 -0.039  0.041  0.014  0.169
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Median Size

response_variable_selected = "median_body_area_µm2"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      2.1   0.378     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1173.7   1201.2   -574.9   1149.7       61 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.4   -0.7    0.1    0.6    2.0 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 3e+05    542           
##             day         1e+03     31      -1.00
##  Residual               4e+05    612           
## Number of obs: 73, groups:  culture_ID, 15
## 
## Fixed effects:
##                                            Estimate Std. Error   df t value
## (Intercept)                                    3800        108   47    35.3
## ecosystem_typeSmall unconnected                -235        166   37    -1.4
## scale(day)                                      268        113   20     2.4
## scale(water_addition_ml)                        105         98   66     1.1
## scale(baseline)                                -110         77   35    -1.4
## ecosystem_typeSmall unconnected:scale(day)      -96        198   19    -0.5
## scale(day):scale(water_addition_ml)             -97        103   70    -0.9
## scale(day):scale(baseline)                     -102         88   17    -1.2
##                                            Pr(>|t|)    
## (Intercept)                                  <2e-16 ***
## ecosystem_typeSmall unconnected                0.17    
## scale(day)                                     0.03 *  
## scale(water_addition_ml)                       0.28    
## scale(baseline)                                0.16    
## ecosystem_typeSmall unconnected:scale(day)     0.63    
## scale(day):scale(water_addition_ml)            0.35    
## scale(day):scale(baseline)                     0.26    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) e_Su:( s():(_
## ecsystm_tSu -0.591                                          
## scale(day)   0.216 -0.171                                   
## scl(wtr_d_)  0.350 -0.280  0.389                            
## scale(bsln) -0.102  0.155 -0.094 -0.188                     
## ecsys_Su:() -0.251  0.216 -0.548 -0.205  0.026              
## scl(d):(__)  0.525 -0.199  0.141  0.487 -0.052 -0.360       
## scl(dy):s() -0.129  0.041 -0.072 -0.091  0.149  0.160 -0.215
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      0.3   0.191     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1172.0   1197.2   -575.0   1150.0       62 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.3   -0.7    0.1    0.6    2.0 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 3e+05    542           
##             day         1e+03     31      -1.00
##  Residual               4e+05    613           
## Number of obs: 73, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error   df t value Pr(>|t|)
## (Intercept)                             3787        104   55      36   <2e-16
## ecosystem_typeSmall unconnected         -217        163   48      -1     0.19
## scale(day)                               238         94   20       2     0.02
## scale(water_addition_ml)                  96         96   69       1     0.32
## scale(baseline)                         -108         77   35      -1     0.17
## scale(day):scale(water_addition_ml)     -115         96   68      -1     0.24
## scale(day):scale(baseline)               -96         87   16      -1     0.29
##                                        
## (Intercept)                         ***
## ecosystem_typeSmall unconnected        
## scale(day)                          *  
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Su scl(d) sc(__) scl(b) s():(_
## ecsystm_tSu -0.568                                   
## scale(day)   0.096 -0.065                            
## scl(wtr_d_)  0.315 -0.246  0.338                     
## scale(bsln) -0.099  0.153 -0.096 -0.186              
## scl(d):(__)  0.481 -0.133 -0.072  0.453 -0.046       
## scl(dy):s() -0.093  0.007  0.020 -0.061  0.146 -0.171
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Populations

for(eco_type_i in 1:length(ecosystem_type_selected)){
  
  print(ecosystem_type_selected[eco_type_i])

  p = ds_ecosystems %>%
  filter(ecosystem_type == ecosystem_type_selected[eco_type_i]) %>%
  group_by(day) %>%
  summarise(Ble = mean(Ble_indiv_per_ml_dominance, na.rm = TRUE),
            Cep = mean(Cep_indiv_per_ml_dominance, na.rm = TRUE),
            Col = mean(Col_indiv_per_ml_dominance, na.rm = TRUE),
            Eug = mean(Eug_indiv_per_ml_dominance, na.rm = TRUE),
            Eup = mean(Eup_indiv_per_ml_dominance, na.rm = TRUE),
            Lox = mean(Lox_indiv_per_ml_dominance, na.rm = TRUE),
            Pau = mean(Pau_indiv_per_ml_dominance, na.rm = TRUE),
            Pca = mean(Pca_indiv_per_ml_dominance, na.rm = TRUE),
            Spi = mean(Spi_indiv_per_ml_dominance, na.rm = TRUE),
            Spi_te = mean(Spi_te_indiv_per_ml_dominance, na.rm = TRUE),
            Tet = mean(Tet_indiv_per_ml_dominance, na.rm = TRUE)) %>%
    pivot_longer(Ble:Tet, names_to = "species", values_to = "species_indiv_per_ml") %>%
    ggplot(aes(x = day,
               y = species_indiv_per_ml,
               group = interaction(day, species),
               color = species)) +
  geom_point(position = position_dodge(dodging),
             size = treatment_points_size) +
  geom_line(aes(group = species),
            position = position_dodge(dodging),
            linewidth = treatment_lines_linewidth) + 
    labs(x = axis_names %>% 
           filter(variable == "day") %>% 
           pull(axis_name),
         y = axis_names %>% 
           filter(variable == "dominance") %>% 
           pull(axis_name)) +
    coord_cartesian(ylim = c(0, 100))
  
  print(p)

}
## [1] "Small connected to small"

## [1] "Small unconnected"

Evaporation

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       "water_addition_ml")

\(L_{S}\) vs \(L\)

ecosystem_type_selected = c("Large connected to small",
                     "Large unconnected")

Shannon

response_variable_selected = "shannon"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value    evidence
## 1     -3.3   0.026 ** moderate
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     22.5     45.4      0.8     -1.5       38 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -3.1   -0.5   -0.1    0.6    2.5 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e-01    0.37          
##             day         2e-04    0.02     -1.00
##  Residual               5e-02    0.22          
## Number of obs: 50, groups:  culture_ID, 10
## 
## Fixed effects:
##                                            Estimate Std. Error    df t value
## (Intercept)                                    1.39       0.06 25.43    22.0
## ecosystem_typeLarge unconnected                0.10       0.08 17.34     1.2
## scale(day)                                     0.13       0.07 12.41     2.0
## scale(water_addition_ml)                      -0.04       0.07 39.92    -0.6
## scale(baseline)                                0.02       0.04 15.29     0.5
## ecosystem_typeLarge unconnected:scale(day)    -0.32       0.10 12.51    -3.3
## scale(day):scale(water_addition_ml)           -0.05       0.06 43.23    -0.8
## scale(day):scale(baseline)                     0.08       0.05 10.30     1.7
##                                            Pr(>|t|)    
## (Intercept)                                  <2e-16 ***
## ecosystem_typeLarge unconnected               0.261    
## scale(day)                                    0.068 .  
## scale(water_addition_ml)                      0.560    
## scale(baseline)                               0.604    
## ecosystem_typeLarge unconnected:scale(day)    0.006 ** 
## scale(day):scale(water_addition_ml)           0.439    
## scale(day):scale(baseline)                    0.121    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) e_Lu:( s():(_
## ecsystm_tLu -0.642                                          
## scale(day)  -0.105  0.179                                   
## scl(wtr_d_)  0.514 -0.178  0.319                            
## scale(bsln)  0.184 -0.355 -0.103 -0.046                     
## ecsys_Lu:()  0.121 -0.384 -0.678 -0.050  0.148              
## scl(d):(__)  0.498  0.013  0.275  0.789 -0.091 -0.252       
## scl(dy):s() -0.076  0.145  0.243 -0.027 -0.347 -0.366  0.035
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.9   0.737     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     27.6     48.7     -2.8      5.6       39 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.7   -0.6   -0.1    0.6    2.6 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 4e-01    0.67          
##             day         8e-04    0.03     -1.00
##  Residual               5e-02    0.22          
## Number of obs: 50, groups:  culture_ID, 10
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             1.43       0.07 23.08    21.4   <2e-16
## ecosystem_typeLarge unconnected        -0.03       0.08 30.98    -0.4      0.7
## scale(day)                             -0.02       0.07 12.99    -0.3      0.8
## scale(water_addition_ml)               -0.06       0.07 39.37    -0.8      0.4
## scale(baseline)                         0.05       0.04  9.82     1.0      0.3
## scale(day):scale(water_addition_ml)    -0.10       0.06 42.34    -1.6      0.1
## scale(day):scale(baseline)              0.02       0.06 10.15     0.4      0.7
##                                        
## (Intercept)                         ***
## ecosystem_typeLarge unconnected        
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) s():(_
## ecsystm_tLu -0.618                                   
## scale(day)  -0.241 -0.084                            
## scl(wtr_d_)  0.506 -0.220  0.281                     
## scale(bsln)  0.141 -0.288 -0.003 -0.034              
## scl(d):(__)  0.547 -0.111  0.089  0.790 -0.044       
## scl(dy):s() -0.025  0.004 -0.003 -0.034 -0.540 -0.045
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Biomass

response_variable_selected = "bioarea_mm2_per_ml"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1     -0.8   0.092   * weak
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    133.1    156.0    -54.5    109.1       38 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -1.8   -0.6   -0.1    0.5    1.7 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1.235    1.11          
##             day         0.002    0.04     -0.89
##  Residual               0.330    0.57          
## Number of obs: 50, groups:  culture_ID, 10
## 
## Fixed effects:
##                                            Estimate Std. Error    df t value
## (Intercept)                                    2.39       0.28 12.38     8.5
## ecosystem_typeLarge unconnected                0.92       0.39 10.37     2.4
## scale(day)                                    -0.72       0.17 11.63    -4.2
## scale(water_addition_ml)                       0.24       0.19 35.26     1.3
## scale(baseline)                                0.15       0.19  9.84     0.8
## ecosystem_typeLarge unconnected:scale(day)     0.06       0.25 11.46     0.3
## scale(day):scale(water_addition_ml)            0.07       0.17 38.89     0.4
## scale(day):scale(baseline)                    -0.06       0.12  9.38    -0.5
##                                            Pr(>|t|)    
## (Intercept)                                   2e-06 ***
## ecosystem_typeLarge unconnected               0.039 *  
## scale(day)                                    0.001 ** 
## scale(water_addition_ml)                      0.212    
## scale(baseline)                               0.450    
## ecosystem_typeLarge unconnected:scale(day)    0.805    
## scale(day):scale(water_addition_ml)           0.676    
## scale(day):scale(baseline)                    0.620    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) e_Lu:( s():(_
## ecsystm_tLu -0.687                                          
## scale(day)  -0.031  0.072                                   
## scl(wtr_d_)  0.320 -0.107  0.335                            
## scale(bsln) -0.144  0.222  0.030  0.017                     
## ecsys_Lu:()  0.048 -0.182 -0.663 -0.063 -0.042              
## scl(d):(__)  0.314 -0.009  0.281  0.802  0.027 -0.250       
## scl(dy):s()  0.028 -0.042 -0.144  0.024 -0.158  0.221 -0.003
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value    evidence
## 1     -2.7    0.03 ** moderate
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    131.1    152.2    -54.6    109.1       39 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -1.8   -0.6   -0.1    0.5    1.7 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1.218    1.10          
##             day         0.002    0.04     -0.89
##  Residual               0.331    0.58          
## Number of obs: 50, groups:  culture_ID, 10
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             2.39       0.28 12.60     8.5    1e-06
## ecosystem_typeLarge unconnected         0.93       0.38 10.34     2.5     0.03
## scale(day)                             -0.69       0.13 14.83    -5.4    8e-05
## scale(water_addition_ml)                0.25       0.19 35.29     1.3     0.21
## scale(baseline)                         0.15       0.19  9.87     0.8     0.44
## scale(day):scale(water_addition_ml)     0.08       0.17 40.42     0.5     0.62
## scale(day):scale(baseline)             -0.07       0.11  9.32    -0.6     0.57
##                                        
## (Intercept)                         ***
## ecosystem_typeLarge unconnected     *  
## scale(day)                          ***
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) s():(_
## ecsystm_tLu -0.691                                   
## scale(day)   0.005 -0.067                            
## scl(wtr_d_)  0.325 -0.120  0.392                     
## scale(bsln) -0.142  0.219  0.003  0.014              
## scl(d):(__)  0.338 -0.056  0.160  0.814  0.018       
## scl(dy):s()  0.018 -0.002  0.004  0.039 -0.147  0.056
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Richness

response_variable_selected = "species_richness"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      3.2   0.671     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    186.7    209.6    -81.3    162.7       38 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.8   -0.6    0.2    0.7    1.8 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 9e-01    0.94          
##             day         1e-04    0.01     -1.00
##  Residual               1e+00    1.10          
## Number of obs: 50, groups:  culture_ID, 10
## 
## Fixed effects:
##                                            Estimate Std. Error    df t value
## (Intercept)                                    6.38       0.42 14.02    15.1
## ecosystem_typeLarge unconnected                0.51       0.56 10.68     0.9
## scale(day)                                     0.29       0.25 37.75     1.2
## scale(water_addition_ml)                       0.27       0.36 40.66     0.7
## scale(baseline)                                0.05       0.28  9.87     0.2
## ecosystem_typeLarge unconnected:scale(day)    -0.07       0.35 36.57    -0.2
## scale(day):scale(water_addition_ml)           -0.21       0.31 41.21    -0.7
## scale(day):scale(baseline)                     0.33       0.16 35.50     2.0
##                                            Pr(>|t|)    
## (Intercept)                                   5e-10 ***
## ecosystem_typeLarge unconnected                0.38    
## scale(day)                                     0.25    
## scale(water_addition_ml)                       0.46    
## scale(baseline)                                0.85    
## ecosystem_typeLarge unconnected:scale(day)     0.83    
## scale(day):scale(water_addition_ml)            0.51    
## scale(day):scale(baseline)                     0.05 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) e_Lu:( s():(_
## ecsystm_tLu -0.668                                          
## scale(day)   0.080  0.010                                   
## scl(wtr_d_)  0.394 -0.143  0.427                            
## scale(bsln)  0.023 -0.059 -0.030 -0.059                     
## ecsys_Lu:() -0.013 -0.150 -0.620 -0.072  0.008              
## scl(d):(__)  0.389 -0.024  0.353  0.804 -0.042 -0.300       
## scl(dy):s() -0.044  0.006  0.011 -0.075 -0.106 -0.027 -0.107
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.2   0.385     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    184.7    205.8    -81.4    162.7       39 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.8   -0.6    0.2    0.6    1.8 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 9e-01    0.97          
##             day         2e-04    0.01     -1.00
##  Residual               1e+00    1.10          
## Number of obs: 50, groups:  culture_ID, 10
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             6.38       0.42 13.99    15.1    5e-10
## ecosystem_typeLarge unconnected         0.49       0.55 10.74     0.9     0.39
## scale(day)                              0.26       0.20 38.24     1.3     0.19
## scale(water_addition_ml)                0.26       0.36 40.80     0.7     0.47
## scale(baseline)                         0.05       0.28  9.90     0.2     0.85
## scale(day):scale(water_addition_ml)    -0.23       0.30 41.30    -0.8     0.45
## scale(day):scale(baseline)              0.33       0.16 34.71     2.0     0.05
##                                        
## (Intercept)                         ***
## ecosystem_typeLarge unconnected        
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)          .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) s():(_
## ecsystm_tLu -0.678                                   
## scale(day)   0.084 -0.105                            
## scl(wtr_d_)  0.394 -0.156  0.488                     
## scale(bsln)  0.024 -0.059 -0.032 -0.058              
## scl(d):(__)  0.405 -0.076  0.222  0.822 -0.041       
## scl(dy):s() -0.045  0.003 -0.007 -0.077 -0.116 -0.120
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Evenness

response_variable_selected = "evenness_pielou"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value   evidence
## 1     -6.4   0.006 *** strong
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    -75.8    -52.8     49.9    -99.8       38 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.08  -0.64  -0.02   0.73   1.96 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e-02    0.120         
##             day         4e-05    0.007    -1.00
##  Residual               7e-03    0.082         
## Number of obs: 50, groups:  culture_ID, 10
## 
## Fixed effects:
##                                            Estimate Std. Error     df t value
## (Intercept)                                   0.764      0.023 20.862    33.6
## ecosystem_typeLarge unconnected               0.032      0.029 12.760     1.1
## scale(day)                                    0.036      0.026 12.158     1.4
## scale(water_addition_ml)                     -0.047      0.027 37.379    -1.7
## scale(baseline)                              -0.012      0.014 10.450    -0.9
## ecosystem_typeLarge unconnected:scale(day)   -0.149      0.038 12.605    -3.9
## scale(day):scale(water_addition_ml)          -0.005      0.025 40.826    -0.2
## scale(day):scale(baseline)                    0.018      0.018 10.512     1.0
##                                            Pr(>|t|)    
## (Intercept)                                  <2e-16 ***
## ecosystem_typeLarge unconnected               0.279    
## scale(day)                                    0.187    
## scale(water_addition_ml)                      0.094 .  
## scale(baseline)                               0.383    
## ecosystem_typeLarge unconnected:scale(day)    0.002 ** 
## scale(day):scale(water_addition_ml)           0.847    
## scale(day):scale(baseline)                    0.341    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) e_Lu:( s():(_
## ecsystm_tLu -0.633                                          
## scale(day)   0.339 -0.174                                   
## scl(wtr_d_)  0.580 -0.216  0.326                            
## scale(bsln)  0.204 -0.382  0.047  0.032                     
## ecsys_Lu:() -0.200  0.080 -0.691 -0.082 -0.010              
## scl(d):(__)  0.554 -0.009  0.300  0.812 -0.064 -0.273       
## scl(dy):s()  0.084 -0.017  0.266  0.034  0.154 -0.397  0.135
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.1   0.331     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    -68.3    -47.3     45.2    -90.3       39 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -1.85  -0.61  -0.07   0.64   1.94 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 6e-02    0.25          
##             day         2e-04    0.01     -1.00
##  Residual               7e-03    0.08          
## Number of obs: 50, groups:  culture_ID, 10
## 
## Fixed effects:
##                                     Estimate Std. Error     df t value Pr(>|t|)
## (Intercept)                            0.750      0.023 21.023    32.8   <2e-16
## ecosystem_typeLarge unconnected        0.043      0.029 12.991     1.5     0.16
## scale(day)                            -0.036      0.028 11.619    -1.3     0.22
## scale(water_addition_ml)              -0.054      0.028 35.273    -1.9     0.06
## scale(baseline)                       -0.014      0.014  9.384    -1.0     0.35
## scale(day):scale(water_addition_ml)   -0.021      0.025 38.997    -0.8     0.40
## scale(day):scale(baseline)            -0.009      0.027  9.561    -0.4     0.73
##                                        
## (Intercept)                         ***
## ecosystem_typeLarge unconnected        
## scale(day)                             
## scale(water_addition_ml)            .  
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) s():(_
## ecsystm_tLu -0.617                                   
## scale(day)   0.249 -0.113                            
## scl(wtr_d_)  0.581 -0.201  0.249                     
## scale(bsln)  0.197 -0.380  0.038  0.025              
## scl(d):(__)  0.537  0.028  0.095  0.817 -0.078       
## scl(dy):s()  0.005  0.011 -0.006  0.002  0.210  0.022
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Median Size

response_variable_selected = "median_body_area_µm2"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value   evidence
## 1     -7.7   0.003 *** strong
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    768.9    791.8   -372.4    744.9       38 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -1.75  -0.48  -0.08   0.38   2.82 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr
##  culture_ID (Intercept) 1e+04     98          
##             day         5e+00      2      1.00
##  Residual               2e+05    395          
## Number of obs: 50, groups:  culture_ID, 10
## 
## Fixed effects:
##                                            Estimate Std. Error   df t value
## (Intercept)                                    3661        122   17    30.0
## ecosystem_typeLarge unconnected                  60        160   11     0.4
## scale(day)                                      252         91   40     2.8
## scale(water_addition_ml)                       -295        128   43    -2.3
## scale(baseline)                                  30         79   10     0.4
## ecosystem_typeLarge unconnected:scale(day)     -490        130   40    -3.8
## scale(day):scale(water_addition_ml)             -48        112   43    -0.4
## scale(day):scale(baseline)                       44         63   39     0.7
##                                            Pr(>|t|)    
## (Intercept)                                   4e-16 ***
## ecosystem_typeLarge unconnected               0.714    
## scale(day)                                    0.009 ** 
## scale(water_addition_ml)                      0.026 *  
## scale(baseline)                               0.711    
## ecosystem_typeLarge unconnected:scale(day)    5e-04 ***
## scale(day):scale(water_addition_ml)           0.672    
## scale(day):scale(baseline)                    0.496    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) e_Lu:( s():(_
## ecsystm_tLu -0.664                                          
## scale(day)   0.219 -0.093                                   
## scl(wtr_d_)  0.473 -0.149  0.399                            
## scale(bsln) -0.217  0.354  0.024  0.083                     
## ecsys_Lu:() -0.104 -0.007 -0.647 -0.050  0.033              
## scl(d):(__)  0.480 -0.023  0.307  0.810  0.030 -0.232       
## scl(dy):s()  0.056  0.033 -0.229  0.081  0.038  0.299  0.167
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.9   0.704     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    778.4    799.4   -378.2    756.4       39 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -1.8   -0.5   -0.1    0.6    2.7 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 2e+05    439           
##             day         6e+02     25      -0.97
##  Residual               2e+05    432           
## Number of obs: 50, groups:  culture_ID, 10
## 
## Fixed effects:
##                                     Estimate Std. Error   df t value Pr(>|t|)
## (Intercept)                             3591        126   18    28.4   <2e-16
## ecosystem_typeLarge unconnected          124        163   11     0.8     0.46
## scale(day)                                21         89   16     0.2     0.82
## scale(water_addition_ml)                -321        143   37    -2.2     0.03
## scale(baseline)                           49         81    9     0.6     0.56
## scale(day):scale(water_addition_ml)     -124        124   43    -1.0     0.32
## scale(day):scale(baseline)               121         80   11     1.5     0.16
##                                        
## (Intercept)                         ***
## ecosystem_typeLarge unconnected        
## scale(day)                             
## scale(water_addition_ml)            *  
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) s():(_
## ecsystm_tLu -0.643                                   
## scale(day)   0.266 -0.127                            
## scl(wtr_d_)  0.509 -0.152  0.414                     
## scale(bsln) -0.194  0.341  0.052  0.094              
## scl(d):(__)  0.498  0.002  0.179  0.825  0.051       
## scl(dy):s()  0.083  0.044 -0.035  0.093  0.164  0.222
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Populations

for(eco_type_i in 1:length(ecosystem_type_selected)){
  
  print(ecosystem_type_selected[eco_type_i])

  p = ds_ecosystems %>%
  filter(ecosystem_type == ecosystem_type_selected[eco_type_i]) %>%
  group_by(day) %>%
  summarise(Ble = mean(Ble_indiv_per_ml_dominance, na.rm = TRUE),
            Cep = mean(Cep_indiv_per_ml_dominance, na.rm = TRUE),
            Col = mean(Col_indiv_per_ml_dominance, na.rm = TRUE),
            Eug = mean(Eug_indiv_per_ml_dominance, na.rm = TRUE),
            Eup = mean(Eup_indiv_per_ml_dominance, na.rm = TRUE),
            Lox = mean(Lox_indiv_per_ml_dominance, na.rm = TRUE),
            Pau = mean(Pau_indiv_per_ml_dominance, na.rm = TRUE),
            Pca = mean(Pca_indiv_per_ml_dominance, na.rm = TRUE),
            Spi = mean(Spi_indiv_per_ml_dominance, na.rm = TRUE),
            Spi_te = mean(Spi_te_indiv_per_ml_dominance, na.rm = TRUE),
            Tet = mean(Tet_indiv_per_ml_dominance, na.rm = TRUE)) %>%
    pivot_longer(Ble:Tet, names_to = "species", values_to = "species_indiv_per_ml") %>%
    ggplot(aes(x = day,
               y = species_indiv_per_ml,
               group = interaction(day, species),
               color = species)) +
  geom_point(position = position_dodge(dodging),
             size = treatment_points_size) +
  geom_line(aes(group = species),
            position = position_dodge(dodging),
            linewidth = treatment_lines_linewidth) + 
    labs(x = axis_names %>% 
           filter(variable == "day") %>% 
           pull(axis_name),
         y = axis_names %>% 
           filter(variable == "dominance") %>% 
           pull(axis_name)) +
    coord_cartesian(ylim = c(0, 100))
  
  print(p)

}
## [1] "Large connected to small"

## [1] "Large unconnected"

Evaporation

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       "water_addition_ml")

\(L_{S}\) vs \(L_{L}\)

ecosystem_type_selected = c("Large connected to small",
                 "Large connected to large")

Shannon

response_variable_selected = "shannon"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.3   0.255     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     30.1     57.9     -3.0      6.1       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.9   -0.7    0.1    0.7    2.3 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 2e-02    0.132         
##             day         3e-05    0.006    -1.00
##  Residual               6e-02    0.249         
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                                   Estimate Std. Error     df
## (Intercept)                                          1.434      0.045 57.121
## ecosystem_typeLarge connected to small              -0.008      0.063 38.515
## scale(day)                                           0.026      0.044 32.058
## scale(water_addition_ml)                             0.065      0.054 63.330
## scale(baseline)                                     -0.028      0.030 39.397
## ecosystem_typeLarge connected to small:scale(day)    0.113      0.066 19.963
## scale(day):scale(water_addition_ml)                  0.035      0.046 68.478
## scale(day):scale(baseline)                           0.048      0.032 20.662
##                                                   t value Pr(>|t|)    
## (Intercept)                                          31.8   <2e-16 ***
## ecosystem_typeLarge connected to small               -0.1      0.9    
## scale(day)                                            0.6      0.6    
## scale(water_addition_ml)                              1.2      0.2    
## scale(baseline)                                      -0.9      0.4    
## ecosystem_typeLarge connected to small:scale(day)     1.7      0.1    
## scale(day):scale(water_addition_ml)                   0.8      0.5    
## scale(day):scale(baseline)                            1.5      0.1    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ec_Lcts scl(d) sc(__) scl(b) e_Lcts: s():(_
## ecsyst_Lcts -0.537                                            
## scale(day)   0.031  0.054                                     
## scl(wtr_d_)  0.412 -0.030   0.467                             
## scale(bsln) -0.088  0.114  -0.113 -0.183                      
## ecs_Lcts:()  0.014 -0.058  -0.574 -0.138  0.031               
## scl(d):(__)  0.603 -0.126   0.141  0.733 -0.064 -0.025        
## scl(dy):s() -0.128  0.032  -0.027 -0.072 -0.055  0.108  -0.209
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1        2   0.943     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     30.8     56.3     -4.4      8.8       64 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.86  -0.80   0.07   0.70   2.36 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 5e-02    0.23          
##             day         1e-04    0.01     -1.00
##  Residual               6e-02    0.25          
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                        Estimate Std. Error     df t value
## (Intercept)                               1.427      0.046 53.161    31.3
## ecosystem_typeLarge connected to small    0.005      0.064 38.685     0.1
## scale(day)                                0.069      0.039 25.653     1.8
## scale(water_addition_ml)                  0.073      0.054 61.824     1.4
## scale(baseline)                          -0.030      0.031 31.678    -1.0
## scale(day):scale(water_addition_ml)       0.031      0.047 65.760     0.7
## scale(day):scale(baseline)                0.043      0.034 16.604     1.3
##                                        Pr(>|t|)    
## (Intercept)                              <2e-16 ***
## ecosystem_typeLarge connected to small     0.94    
## scale(day)                                 0.08 .  
## scale(water_addition_ml)                   0.18    
## scale(baseline)                            0.34    
## scale(day):scale(water_addition_ml)        0.51    
## scale(day):scale(baseline)                 0.22    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) e_Lcts scl(d) sc(__) scl(b) s():(_
## ecsyst_Lcts -0.537                                   
## scale(day)   0.012  0.020                            
## scl(wtr_d_)  0.418 -0.044  0.455                     
## scale(bsln) -0.087  0.117 -0.112 -0.182              
## scl(d):(__)  0.605 -0.131  0.141  0.731 -0.061       
## scl(dy):s() -0.123  0.036  0.040 -0.053 -0.111 -0.196
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Biomass

response_variable_selected = "bioarea_mm2_per_ml"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      2.9   0.565     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    192.0    219.8    -84.0    168.0       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -1.69  -0.73  -0.09   0.64   2.42 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 0.921    0.96          
##             day         0.001    0.04     -1.00
##  Residual               0.473    0.69          
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                                   Estimate Std. Error     df
## (Intercept)                                          2e+00      1e-01  2e+01
## ecosystem_typeLarge connected to small              -1e-01      2e-01  2e+01
## scale(day)                                          -6e-01      1e-01  2e+01
## scale(water_addition_ml)                             1e-01      1e-01  6e+01
## scale(baseline)                                      5e-04      1e-01  1e+01
## ecosystem_typeLarge connected to small:scale(day)   -1e-01      2e-01  2e+01
## scale(day):scale(water_addition_ml)                  4e-02      1e-01  6e+01
## scale(day):scale(baseline)                          -9e-02      1e-01  2e+01
##                                                   t value Pr(>|t|)    
## (Intercept)                                          16.9    5e-15 ***
## ecosystem_typeLarge connected to small               -0.5      0.6    
## scale(day)                                           -4.6    1e-04 ***
## scale(water_addition_ml)                              0.8      0.4    
## scale(baseline)                                       0.0      1.0    
## ecosystem_typeLarge connected to small:scale(day)    -0.7      0.5    
## scale(day):scale(water_addition_ml)                   0.3      0.7    
## scale(day):scale(baseline)                           -0.9      0.4    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ec_Lcts scl(d) sc(__) scl(b) e_Lcts: s():(_
## ecsyst_Lcts -0.546                                            
## scale(day)  -0.235  0.211                                     
## scl(wtr_d_)  0.321  0.001   0.424                             
## scale(bsln)  0.010 -0.010  -0.009 -0.003                      
## ecs_Lcts:()  0.184 -0.358  -0.575 -0.117  0.006               
## scl(d):(__)  0.504 -0.096   0.093  0.705  0.012  0.010        
## scl(dy):s() -0.031  0.010   0.011 -0.021 -0.349 -0.012  -0.057
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.3   0.409     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    190.5    216.0    -84.2    168.5       64 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -1.7   -0.7   -0.1    0.7    2.3 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 0.958    0.98          
##             day         0.001    0.04     -1.00
##  Residual               0.476    0.69          
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                        Estimate Std. Error     df t value
## (Intercept)                               3e+00      1e-01  3e+01    17.3
## ecosystem_typeLarge connected to small   -2e-01      2e-01  2e+01    -0.8
## scale(day)                               -7e-01      1e-01  2e+01    -6.1
## scale(water_addition_ml)                  1e-01      1e-01  6e+01     0.7
## scale(baseline)                           8e-04      1e-01  1e+01     0.0
## scale(day):scale(water_addition_ml)       4e-02      1e-01  6e+01     0.3
## scale(day):scale(baseline)               -9e-02      1e-01  1e+01    -0.9
##                                        Pr(>|t|)    
## (Intercept)                               3e-16 ***
## ecosystem_typeLarge connected to small      0.4    
## scale(day)                                3e-06 ***
## scale(water_addition_ml)                    0.5    
## scale(baseline)                             1.0    
## scale(day):scale(water_addition_ml)         0.8    
## scale(day):scale(baseline)                  0.4    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) e_Lcts scl(d) sc(__) scl(b) s():(_
## ecsyst_Lcts -0.523                                   
## scale(day)  -0.164  0.007                            
## scl(wtr_d_)  0.352 -0.045  0.436                     
## scale(bsln)  0.010 -0.009 -0.007 -0.003              
## scl(d):(__)  0.513 -0.100  0.120  0.710  0.012       
## scl(dy):s() -0.029  0.006  0.005 -0.023 -0.353 -0.056
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Richness

response_variable_selected = "species_richness"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      3.6     0.8     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    272.9    300.7   -124.4    248.9       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.68  -0.57  -0.03   0.73   2.48 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 3e-01    0.566         
##             day         6e-06    0.003    -1.00
##  Residual               1e+00    1.190         
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                                   Estimate Std. Error   df
## (Intercept)                                            6.3        0.3 23.6
## ecosystem_typeLarge connected to small                 0.2        0.4 15.0
## scale(day)                                             0.2        0.2 62.0
## scale(water_addition_ml)                               0.6        0.3 62.2
## scale(baseline)                                       -0.1        0.2 15.6
## ecosystem_typeLarge connected to small:scale(day)      0.1        0.3 59.5
## scale(day):scale(water_addition_ml)                    0.2        0.2 65.0
## scale(day):scale(baseline)                             0.2        0.1 60.1
##                                                   t value Pr(>|t|)    
## (Intercept)                                          23.3   <2e-16 ***
## ecosystem_typeLarge connected to small                0.6     0.58    
## scale(day)                                            1.0     0.33    
## scale(water_addition_ml)                              2.3     0.03 *  
## scale(baseline)                                      -0.6     0.58    
## ecosystem_typeLarge connected to small:scale(day)     0.3     0.75    
## scale(day):scale(water_addition_ml)                   1.1     0.29    
## scale(day):scale(baseline)                            1.7     0.10    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ec_Lcts scl(d) sc(__) scl(b) e_Lcts: s():(_
## ecsyst_Lcts -0.547                                            
## scale(day)   0.010  0.068                                     
## scl(wtr_d_)  0.324  0.019   0.478                             
## scale(bsln)  0.062 -0.160  -0.122 -0.167                      
## ecs_Lcts:()  0.044 -0.049  -0.585 -0.126  0.047               
## scl(d):(__)  0.495 -0.084   0.117  0.737 -0.043  0.042        
## scl(dy):s() -0.145  0.047   0.141 -0.071 -0.043 -0.188  -0.268
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.7   0.559     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    271.0    296.4   -124.5    249.0       64 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.68  -0.57  -0.06   0.75   2.51 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 3e-01    0.585         
##             day         1e-05    0.003    -1.00
##  Residual               1e+00    1.190         
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                        Estimate Std. Error   df t value
## (Intercept)                                 6.3        0.3 23.6    23.2
## ecosystem_typeLarge connected to small      0.2        0.4 15.1     0.6
## scale(day)                                  0.2        0.2 62.1     1.5
## scale(water_addition_ml)                    0.6        0.3 62.0     2.4
## scale(baseline)                            -0.1        0.2 15.6    -0.6
## scale(day):scale(water_addition_ml)         0.2        0.2 64.8     1.1
## scale(day):scale(baseline)                  0.3        0.1 59.9     1.8
##                                        Pr(>|t|)    
## (Intercept)                              <2e-16 ***
## ecosystem_typeLarge connected to small     0.56    
## scale(day)                                 0.15    
## scale(water_addition_ml)                   0.02 *  
## scale(baseline)                            0.57    
## scale(day):scale(water_addition_ml)        0.29    
## scale(day):scale(baseline)                 0.08 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) e_Lcts scl(d) sc(__) scl(b) s():(_
## ecsyst_Lcts -0.546                                   
## scale(day)   0.041  0.047                            
## scl(wtr_d_)  0.332  0.012  0.502                     
## scale(bsln)  0.060 -0.158 -0.116 -0.162              
## scl(d):(__)  0.493 -0.081  0.175  0.748 -0.045       
## scl(dy):s() -0.139  0.038  0.039 -0.097 -0.040 -0.265
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Evenness

response_variable_selected = "evenness_pielou"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.8   0.325     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   -110.1    -82.3     67.1   -134.1       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -3.1   -0.6    0.2    0.6    1.9 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e-03    0.037         
##             day         4e-06    0.002    -1.00
##  Residual               1e-02    0.098         
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                                   Estimate Std. Error     df
## (Intercept)                                          0.787      0.018 69.484
## ecosystem_typeLarge connected to small              -0.009      0.026 60.527
## scale(day)                                           0.001      0.018 26.044
## scale(water_addition_ml)                            -0.014      0.021 71.192
## scale(baseline)                                     -0.004      0.012 59.822
## ecosystem_typeLarge connected to small:scale(day)    0.042      0.027 15.842
## scale(day):scale(water_addition_ml)                  0.002      0.018 69.912
## scale(day):scale(baseline)                           0.009      0.013 14.963
##                                                   t value Pr(>|t|)    
## (Intercept)                                          44.5   <2e-16 ***
## ecosystem_typeLarge connected to small               -0.3      0.7    
## scale(day)                                            0.1      0.9    
## scale(water_addition_ml)                             -0.6      0.5    
## scale(baseline)                                      -0.3      0.7    
## ecosystem_typeLarge connected to small:scale(day)     1.5      0.1    
## scale(day):scale(water_addition_ml)                   0.1      0.9    
## scale(day):scale(baseline)                            0.7      0.5    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ec_Lcts scl(d) sc(__) scl(b) e_Lcts: s():(_
## ecsyst_Lcts -0.553                                            
## scale(day)   0.039  0.057                                     
## scl(wtr_d_)  0.390  0.013   0.448                             
## scale(bsln) -0.186  0.377   0.039  0.052                      
## ecs_Lcts:()  0.024 -0.024  -0.600 -0.117 -0.013               
## scl(d):(__)  0.587 -0.106   0.122  0.742  0.003  0.022        
## scl(dy):s()  0.040 -0.013  -0.214  0.005  0.001  0.378   0.062
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.9    0.77     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   -109.9    -84.5     66.0   -131.9       64 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -3.1   -0.5    0.2    0.6    1.9 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 5e-03    0.071         
##             day         1e-05    0.004    -1.00
##  Residual               1e-02    0.098         
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                        Estimate Std. Error     df t value
## (Intercept)                               8e-01      2e-02  7e+01    44.1
## ecosystem_typeLarge connected to small   -8e-03      3e-02  6e+01    -0.3
## scale(day)                                2e-02      1e-02  2e+01     1.1
## scale(water_addition_ml)                 -1e-02      2e-02  7e+01    -0.5
## scale(baseline)                          -4e-03      1e-02  6e+01    -0.3
## scale(day):scale(water_addition_ml)       9e-05      2e-02  7e+01     0.0
## scale(day):scale(baseline)                2e-03      1e-02  1e+01     0.1
##                                        Pr(>|t|)    
## (Intercept)                              <2e-16 ***
## ecosystem_typeLarge connected to small      0.8    
## scale(day)                                  0.3    
## scale(water_addition_ml)                    0.6    
## scale(baseline)                             0.7    
## scale(day):scale(water_addition_ml)         1.0    
## scale(day):scale(baseline)                  0.9    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) e_Lcts scl(d) sc(__) scl(b) s():(_
## ecsyst_Lcts -0.552                                   
## scale(day)   0.067  0.052                            
## scl(wtr_d_)  0.400  0.010  0.456                     
## scale(bsln) -0.185  0.377  0.038  0.052              
## scl(d):(__)  0.593 -0.108  0.162  0.750  0.003       
## scl(dy):s()  0.032 -0.004  0.016  0.050  0.011  0.055
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Median Size

response_variable_selected = "median_body_area_µm2"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      3.8   0.883     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1183.6   1211.4   -579.8   1159.6       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -1.98  -0.71  -0.03   0.51   2.44 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 9e+04    306           
##             day         5e+02     22      -1.00
##  Residual               3e+05    527           
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                                   Estimate Std. Error   df
## (Intercept)                                           3815        104   34
## ecosystem_typeLarge connected to small                 -74        149   22
## scale(day)                                             326         99   35
## scale(water_addition_ml)                              -169        120   73
## scale(baseline)                                         10         70   21
## ecosystem_typeLarge connected to small:scale(day)      -22        149   24
## scale(day):scale(water_addition_ml)                    -10        102   72
## scale(day):scale(baseline)                             -56         70   23
##                                                   t value Pr(>|t|)    
## (Intercept)                                          36.8   <2e-16 ***
## ecosystem_typeLarge connected to small               -0.5    0.623    
## scale(day)                                            3.3    0.002 ** 
## scale(water_addition_ml)                             -1.4    0.163    
## scale(baseline)                                       0.1    0.891    
## ecosystem_typeLarge connected to small:scale(day)    -0.1    0.883    
## scale(day):scale(water_addition_ml)                  -0.1    0.925    
## scale(day):scale(baseline)                           -0.8    0.429    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ec_Lcts scl(d) sc(__) scl(b) e_Lcts: s():(_
## ecsyst_Lcts -0.532                                            
## scale(day)   0.226 -0.074                                     
## scl(wtr_d_)  0.413 -0.015   0.442                             
## scale(bsln)  0.022 -0.036   0.016  0.021                      
## ecs_Lcts:() -0.103  0.200  -0.573 -0.121 -0.012               
## scl(d):(__)  0.571 -0.103   0.167  0.777  0.010 -0.015        
## scl(dy):s()  0.073 -0.022   0.032  0.085  0.221 -0.036   0.119
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.8   0.633     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1181.6   1207.1   -579.8   1159.6       64 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -1.97  -0.72  -0.06   0.51   2.45 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 9e+04    306           
##             day         5e+02     22      -1.00
##  Residual               3e+05    527           
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                        Estimate Std. Error   df t value
## (Intercept)                                3813        103   38    37.0
## ecosystem_typeLarge connected to small      -70        146   28    -0.5
## scale(day)                                  317         81   35     3.9
## scale(water_addition_ml)                   -171        119   72    -1.4
## scale(baseline)                              10         70   21     0.1
## scale(day):scale(water_addition_ml)         -10        102   72    -0.1
## scale(day):scale(baseline)                  -57         70   23    -0.8
##                                        Pr(>|t|)    
## (Intercept)                              <2e-16 ***
## ecosystem_typeLarge connected to small      0.6    
## scale(day)                                4e-04 ***
## scale(water_addition_ml)                    0.2    
## scale(baseline)                             0.9    
## scale(day):scale(water_addition_ml)         0.9    
## scale(day):scale(baseline)                  0.4    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) e_Lcts scl(d) sc(__) scl(b) s():(_
## ecsyst_Lcts -0.525                                   
## scale(day)   0.204  0.050                            
## scl(wtr_d_)  0.406  0.009  0.458                     
## scale(bsln)  0.021 -0.034  0.011  0.020              
## scl(d):(__)  0.573 -0.102  0.193  0.781  0.010       
## scl(dy):s()  0.069 -0.015  0.014  0.082  0.220  0.119
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Populations

for(eco_type_i in 1:length(ecosystem_type_selected)){
  
  print(ecosystem_type_selected[eco_type_i])

  p = ds_ecosystems %>%
  filter(ecosystem_type == ecosystem_type_selected[eco_type_i]) %>%
  group_by(day) %>%
  summarise(Ble = mean(Ble_indiv_per_ml_dominance, na.rm = TRUE),
            Cep = mean(Cep_indiv_per_ml_dominance, na.rm = TRUE),
            Col = mean(Col_indiv_per_ml_dominance, na.rm = TRUE),
            Eug = mean(Eug_indiv_per_ml_dominance, na.rm = TRUE),
            Eup = mean(Eup_indiv_per_ml_dominance, na.rm = TRUE),
            Lox = mean(Lox_indiv_per_ml_dominance, na.rm = TRUE),
            Pau = mean(Pau_indiv_per_ml_dominance, na.rm = TRUE),
            Pca = mean(Pca_indiv_per_ml_dominance, na.rm = TRUE),
            Spi = mean(Spi_indiv_per_ml_dominance, na.rm = TRUE),
            Spi_te = mean(Spi_te_indiv_per_ml_dominance, na.rm = TRUE),
            Tet = mean(Tet_indiv_per_ml_dominance, na.rm = TRUE)) %>%
    pivot_longer(Ble:Tet, names_to = "species", values_to = "species_indiv_per_ml") %>%
    ggplot(aes(x = day,
               y = species_indiv_per_ml,
               group = interaction(day, species),
               color = species)) +
  geom_point(position = position_dodge(dodging),
             size = treatment_points_size) +
  geom_line(aes(group = species),
            position = position_dodge(dodging),
            linewidth = treatment_lines_linewidth) + 
    labs(x = axis_names %>% 
           filter(variable == "day") %>% 
           pull(axis_name),
         y = axis_names %>% 
           filter(variable == "dominance") %>% 
           pull(axis_name)) +
    coord_cartesian(ylim = c(0, 100))
  
  print(p)

}
## [1] "Large connected to small"

## [1] "Large connected to large"

Evaporation

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       "water_addition_ml")

\(L_{L}\) vs \(L\)

ecosystem_type_selected = c("Large connected to large",
                 "Large unconnected")

Shannon

response_variable_selected = "shannon"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value    evidence
## 1     -3.2   0.028 ** moderate
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     15.4     43.2      4.3     -8.6       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.68  -0.56   0.08   0.75   1.58 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 4e-02    0.21          
##             day         1e-04    0.01     -0.99
##  Residual               5e-02    0.22          
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                            Estimate Std. Error     df t value
## (Intercept)                                   1.448      0.046 35.013    31.2
## ecosystem_typeLarge unconnected               0.088      0.059 14.058     1.5
## scale(day)                                    0.028      0.045 28.477     0.6
## scale(water_addition_ml)                      0.058      0.061 60.982     1.0
## scale(baseline)                               0.014      0.028 13.542     0.5
## ecosystem_typeLarge unconnected:scale(day)   -0.185      0.066 15.987    -2.8
## scale(day):scale(water_addition_ml)           0.045      0.050 64.543     0.9
## scale(day):scale(baseline)                    0.003      0.031 14.701     0.1
##                                            Pr(>|t|)    
## (Intercept)                                  <2e-16 ***
## ecosystem_typeLarge unconnected                0.16    
## scale(day)                                     0.54    
## scale(water_addition_ml)                       0.34    
## scale(baseline)                                0.61    
## ecosystem_typeLarge unconnected:scale(day)     0.01 *  
## scale(day):scale(water_addition_ml)            0.37    
## scale(day):scale(baseline)                     0.92    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) e_Lu:( s():(_
## ecsystm_tLu -0.514                                          
## scale(day)   0.287 -0.113                                   
## scl(wtr_d_)  0.626 -0.218  0.571                            
## scale(bsln) -0.020 -0.188 -0.105 -0.178                     
## ecsys_Lu:() -0.134 -0.028 -0.516 -0.139  0.038              
## scl(d):(__)  0.706 -0.137  0.396  0.823 -0.154 -0.226       
## scl(dy):s() -0.070  0.026  0.069 -0.084 -0.030 -0.209 -0.091
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1        1   0.311     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     19.6     45.0      1.2     -2.4       64 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.68  -0.60   0.05   0.85   1.41 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e-01    0.37          
##             day         3e-04    0.02     -0.99
##  Residual               5e-02    0.22          
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             1.43       0.05 33.62    30.0   <2e-16
## ecosystem_typeLarge unconnected         0.08       0.06 14.22     1.3      0.2
## scale(day)                             -0.04       0.04 28.75    -0.9      0.4
## scale(water_addition_ml)                0.03       0.06 60.01     0.5      0.6
## scale(baseline)                         0.02       0.03 13.45     0.6      0.5
## scale(day):scale(water_addition_ml)     0.01       0.05 63.99     0.2      0.8
## scale(day):scale(baseline)             -0.01       0.04 15.29    -0.4      0.7
##                                        
## (Intercept)                         ***
## ecosystem_typeLarge unconnected        
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) s():(_
## ecsystm_tLu -0.523                                   
## scale(day)   0.205 -0.129                            
## scl(wtr_d_)  0.614 -0.221  0.519                     
## scale(bsln) -0.011 -0.189 -0.086 -0.171              
## scl(d):(__)  0.696 -0.146  0.291  0.819 -0.146       
## scl(dy):s() -0.084  0.017 -0.033 -0.097 -0.053 -0.121
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Biomass

response_variable_selected = "bioarea_mm2_per_ml"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1     -0.6   0.101     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    196.2    224.0    -86.1    172.2       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -1.90  -0.72  -0.07   0.43   2.66 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 0.829    0.91          
##             day         0.001    0.04     -0.82
##  Residual               0.400    0.63          
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                            Estimate Std. Error    df t value
## (Intercept)                                    2.67       0.21 24.11    12.5
## ecosystem_typeLarge unconnected                0.71       0.33 15.39     2.2
## scale(day)                                    -0.48       0.14 29.91    -3.5
## scale(water_addition_ml)                       0.44       0.19 60.41     2.3
## scale(baseline)                                0.02       0.15 14.74     0.1
## ecosystem_typeLarge unconnected:scale(day)    -0.18       0.20 16.88    -0.9
## scale(day):scale(water_addition_ml)            0.28       0.15 61.86     1.8
## scale(day):scale(baseline)                    -0.10       0.09 15.01    -1.1
##                                            Pr(>|t|)    
## (Intercept)                                   5e-12 ***
## ecosystem_typeLarge unconnected               0.046 *  
## scale(day)                                    0.002 ** 
## scale(water_addition_ml)                      0.025 *  
## scale(baseline)                               0.907    
## ecosystem_typeLarge unconnected:scale(day)    0.392    
## scale(day):scale(water_addition_ml)           0.080 .  
## scale(day):scale(baseline)                    0.288    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) e_Lu:( s():(_
## ecsystm_tLu -0.555                                          
## scale(day)   0.206 -0.075                                   
## scl(wtr_d_)  0.438 -0.147  0.589                            
## scale(bsln) -0.059  0.116 -0.004 -0.007                     
## ecsys_Lu:() -0.104 -0.018 -0.519 -0.170 -0.006              
## scl(d):(__)  0.488 -0.099  0.422  0.831  0.002 -0.260       
## scl(dy):s() -0.030 -0.001 -0.071 -0.042 -0.036  0.132 -0.070
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1     -1.8    0.05   * weak
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    195.0    220.5    -86.5    173.0       64 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -1.98  -0.71   0.01   0.44   2.49 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 0.930    0.96          
##             day         0.001    0.04     -0.85
##  Residual               0.400    0.63          
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             2.65       0.21 23.57    12.4    8e-12
## ecosystem_typeLarge unconnected         0.70       0.33 15.43     2.1     0.05
## scale(day)                             -0.55       0.12 33.02    -4.5    7e-05
## scale(water_addition_ml)                0.41       0.19 61.80     2.2     0.03
## scale(baseline)                         0.02       0.15 14.74     0.1     0.91
## scale(day):scale(water_addition_ml)     0.24       0.15 63.68     1.6     0.12
## scale(day):scale(baseline)             -0.09       0.09 14.92    -1.0     0.35
##                                        
## (Intercept)                         ***
## ecosystem_typeLarge unconnected     *  
## scale(day)                          ***
## scale(water_addition_ml)            *  
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) s():(_
## ecsystm_tLu -0.560                                   
## scale(day)   0.168 -0.099                            
## scl(wtr_d_)  0.432 -0.155  0.587                     
## scale(bsln) -0.060  0.116 -0.008 -0.009              
## scl(d):(__)  0.483 -0.112  0.342  0.826  0.000       
## scl(dy):s() -0.017  0.002 -0.002 -0.020 -0.052 -0.036
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Richness

response_variable_selected = "species_richness"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.2   0.243     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    257.1    285.0   -116.6    233.1       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.92  -0.57  -0.01   0.55   2.45 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 3e-01    0.536         
##             day         4e-06    0.002    -1.00
##  Residual               1e+00    1.064         
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                            Estimate Std. Error    df t value
## (Intercept)                                    6.54       0.27 30.09    23.8
## ecosystem_typeLarge unconnected                0.68       0.39 14.98     1.7
## scale(day)                                     0.19       0.20 63.71     0.9
## scale(water_addition_ml)                       0.68       0.31 62.75     2.2
## scale(baseline)                                0.13       0.19 15.15     0.7
## ecosystem_typeLarge unconnected:scale(day)    -0.13       0.28 60.05    -0.5
## scale(day):scale(water_addition_ml)            0.43       0.25 65.24     1.7
## scale(day):scale(baseline)                     0.04       0.13 59.74     0.3
##                                            Pr(>|t|)    
## (Intercept)                                  <2e-16 ***
## ecosystem_typeLarge unconnected                0.10    
## scale(day)                                     0.36    
## scale(water_addition_ml)                       0.03 *  
## scale(baseline)                                0.50    
## ecosystem_typeLarge unconnected:scale(day)     0.65    
## scale(day):scale(water_addition_ml)            0.09 .  
## scale(day):scale(baseline)                     0.74    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) e_Lu:( s():(_
## ecsystm_tLu -0.535                                          
## scale(day)   0.280 -0.096                                   
## scl(wtr_d_)  0.529 -0.154  0.634                            
## scale(bsln)  0.040 -0.211 -0.117 -0.169                     
## ecsys_Lu:() -0.134  0.000 -0.505 -0.164  0.022              
## scl(d):(__)  0.599 -0.106  0.440  0.832 -0.112 -0.244       
## scl(dy):s() -0.110  0.013  0.069 -0.106 -0.009 -0.180 -0.189
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1     -0.6   0.105     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    255.4    280.8   -116.7    233.4       64 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.92  -0.56  -0.03   0.53   2.42 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 3e-01    0.548         
##             day         6e-06    0.003    -1.00
##  Residual               1e+00    1.065         
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             6.52       0.27 28.80    23.9   <2e-16
## ecosystem_typeLarge unconnected         0.68       0.39 15.00     1.7     0.11
## scale(day)                              0.14       0.17 64.25     0.8     0.42
## scale(water_addition_ml)                0.65       0.30 62.97     2.2     0.03
## scale(baseline)                         0.13       0.19 15.17     0.7     0.50
## scale(day):scale(water_addition_ml)     0.40       0.24 65.02     1.7     0.10
## scale(day):scale(baseline)              0.03       0.13 59.92     0.3     0.80
##                                        
## (Intercept)                         ***
## ecosystem_typeLarge unconnected        
## scale(day)                             
## scale(water_addition_ml)            *  
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) s():(_
## ecsystm_tLu -0.540                                   
## scale(day)   0.246 -0.111                            
## scl(wtr_d_)  0.518 -0.157  0.648                     
## scale(bsln)  0.043 -0.211 -0.123 -0.167              
## scl(d):(__)  0.588 -0.110  0.378  0.827 -0.109       
## scl(dy):s() -0.137  0.014 -0.026 -0.140 -0.009 -0.244
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Evenness

response_variable_selected = "evenness_pielou"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value    evidence
## 1     -3.6   0.023 ** moderate
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   -125.3    -97.5     74.7   -149.3       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -3.3   -0.5    0.3    0.6    1.9 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e-02    0.112         
##             day         4e-05    0.006    -1.00
##  Residual               7e-03    0.084         
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                            Estimate Std. Error     df t value
## (Intercept)                                   8e-01      2e-02  6e+01    43.4
## ecosystem_typeLarge unconnected              -2e-04      2e-02  5e+01     0.0
## scale(day)                                    7e-03      2e-02  3e+01     0.4
## scale(water_addition_ml)                     -2e-02      2e-02  7e+01    -0.6
## scale(baseline)                               2e-02      1e-02  5e+01     2.0
## ecosystem_typeLarge unconnected:scale(day)   -9e-02      3e-02  2e+01    -3.1
## scale(day):scale(water_addition_ml)          -7e-03      2e-02  7e+01    -0.4
## scale(day):scale(baseline)                    2e-02      1e-02  2e+01     1.2
##                                            Pr(>|t|)    
## (Intercept)                                  <2e-16 ***
## ecosystem_typeLarge unconnected               0.993    
## scale(day)                                    0.726    
## scale(water_addition_ml)                      0.525    
## scale(baseline)                               0.048 *  
## ecosystem_typeLarge unconnected:scale(day)    0.007 ** 
## scale(day):scale(water_addition_ml)           0.709    
## scale(day):scale(baseline)                    0.257    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) e_Lu:( s():(_
## ecsystm_tLu -0.526                                          
## scale(day)   0.394 -0.222                                   
## scl(wtr_d_)  0.652 -0.268  0.526                            
## scale(bsln) -0.020 -0.053  0.015 -0.002                     
## ecsys_Lu:() -0.216  0.168 -0.528 -0.144  0.014              
## scl(d):(__)  0.728 -0.178  0.373  0.828 -0.064 -0.225       
## scl(dy):s()  0.041  0.004  0.006 -0.005  0.139 -0.068  0.065
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.8   0.622     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   -120.0    -94.5     71.0   -142.0       64 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -3.3   -0.5    0.2    0.6    2.1 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 3e-02    0.174         
##             day         9e-05    0.009    -1.00
##  Residual               7e-03    0.084         
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             0.77       0.02 61.38    43.0   <2e-16
## ecosystem_typeLarge unconnected         0.01       0.02 57.37     0.6     0.56
## scale(day)                             -0.02       0.02 24.97    -1.2     0.23
## scale(water_addition_ml)               -0.02       0.02 64.42    -1.0     0.33
## scale(baseline)                         0.02       0.01 36.26     2.0     0.05
## scale(day):scale(water_addition_ml)    -0.02       0.02 68.33    -0.9     0.38
## scale(day):scale(baseline)              0.01       0.02 15.11     0.8     0.45
##                                        
## (Intercept)                         ***
## ecosystem_typeLarge unconnected        
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                     .  
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) s():(_
## ecsystm_tLu -0.500                                   
## scale(day)   0.341 -0.139                            
## scl(wtr_d_)  0.651 -0.251  0.459                     
## scale(bsln) -0.020 -0.056  0.023 -0.002              
## scl(d):(__)  0.721 -0.143  0.264  0.828 -0.065       
## scl(dy):s()  0.023  0.013 -0.024 -0.011  0.212  0.042
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Median Size

response_variable_selected = "median_body_area_µm2"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value   evidence
## 1     -5.5   0.009 *** strong
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1163.6   1191.4   -569.8   1139.6       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -1.77  -0.66  -0.05   0.42   3.01 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 3e+05    560           
##             day         1e+03     34      -1.00
##  Residual               2e+05    444           
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                            Estimate Std. Error     df t value
## (Intercept)                                  3843.1      103.4   44.0    37.2
## ecosystem_typeLarge unconnected              -118.9      134.1   24.6    -0.9
## scale(day)                                    427.8      105.0   27.9     4.1
## scale(water_addition_ml)                        0.1      130.2   71.4     0.0
## scale(baseline)                                34.8       61.8   22.8     0.6
## ecosystem_typeLarge unconnected:scale(day)   -562.6      159.8   17.5    -3.5
## scale(day):scale(water_addition_ml)            70.7      105.9   72.9     0.7
## scale(day):scale(baseline)                    -54.1       74.4   16.5    -0.7
##                                            Pr(>|t|)    
## (Intercept)                                  <2e-16 ***
## ecosystem_typeLarge unconnected               0.384    
## scale(day)                                    3e-04 ***
## scale(water_addition_ml)                      0.999    
## scale(baseline)                               0.579    
## ecosystem_typeLarge unconnected:scale(day)    0.003 ** 
## scale(day):scale(water_addition_ml)           0.506    
## scale(day):scale(baseline)                    0.478    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) e_Lu:( s():(_
## ecsystm_tLu -0.542                                          
## scale(day)   0.508 -0.303                                   
## scl(wtr_d_)  0.630 -0.240  0.522                            
## scale(bsln) -0.110  0.217 -0.033  0.002                     
## ecsys_Lu:() -0.283  0.365 -0.542 -0.143  0.087              
## scl(d):(__)  0.697 -0.177  0.381  0.849 -0.026 -0.201       
## scl(dy):s()  0.005  0.077 -0.109  0.024  0.351  0.206  0.062
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.8   0.682     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1170.9   1196.4   -574.5   1148.9       64 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -1.48  -0.65  -0.08   0.47   2.96 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 9e+05    953           
##             day         3e+03     55      -1.00
##  Residual               2e+05    448           
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error   df t value Pr(>|t|)
## (Intercept)                             3764        103   45    36.4   <2e-16
## ecosystem_typeLarge unconnected           62        124   48     0.5     0.62
## scale(day)                               240        110   23     2.2     0.04
## scale(water_addition_ml)                 -19        134   67    -0.1     0.89
## scale(baseline)                           55         65   15     0.8     0.41
## scale(day):scale(water_addition_ml)       40        108   70     0.4     0.72
## scale(day):scale(baseline)                 3         97   15     0.0     0.97
##                                        
## (Intercept)                         ***
## ecosystem_typeLarge unconnected        
## scale(day)                          *  
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Lu scl(d) sc(__) scl(b) s():(_
## ecsystm_tLu -0.472                                   
## scale(day)   0.485 -0.114                            
## scl(wtr_d_)  0.622 -0.205  0.443                     
## scale(bsln) -0.079  0.186  0.013  0.014              
## scl(d):(__)  0.679 -0.111  0.276  0.850 -0.007       
## scl(dy):s()  0.053  0.002  0.003  0.044  0.474  0.085
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Populations

for(eco_type_i in 1:length(ecosystem_type_selected)){
  
  print(ecosystem_type_selected[eco_type_i])

  p = ds_ecosystems %>%
  filter(ecosystem_type == ecosystem_type_selected[eco_type_i]) %>%
  group_by(day) %>%
  summarise(Ble = mean(Ble_indiv_per_ml_dominance, na.rm = TRUE),
            Cep = mean(Cep_indiv_per_ml_dominance, na.rm = TRUE),
            Col = mean(Col_indiv_per_ml_dominance, na.rm = TRUE),
            Eug = mean(Eug_indiv_per_ml_dominance, na.rm = TRUE),
            Eup = mean(Eup_indiv_per_ml_dominance, na.rm = TRUE),
            Lox = mean(Lox_indiv_per_ml_dominance, na.rm = TRUE),
            Pau = mean(Pau_indiv_per_ml_dominance, na.rm = TRUE),
            Pca = mean(Pca_indiv_per_ml_dominance, na.rm = TRUE),
            Spi = mean(Spi_indiv_per_ml_dominance, na.rm = TRUE),
            Spi_te = mean(Spi_te_indiv_per_ml_dominance, na.rm = TRUE),
            Tet = mean(Tet_indiv_per_ml_dominance, na.rm = TRUE)) %>%
    pivot_longer(Ble:Tet, names_to = "species", values_to = "species_indiv_per_ml") %>%
    ggplot(aes(x = day,
               y = species_indiv_per_ml,
               group = interaction(day, species),
               color = species)) +
  geom_point(position = position_dodge(dodging),
             size = treatment_points_size) +
  geom_line(aes(group = species),
            position = position_dodge(dodging),
            linewidth = treatment_lines_linewidth) + 
    labs(x = axis_names %>% 
           filter(variable == "day") %>% 
           pull(axis_name),
         y = axis_names %>% 
           filter(variable == "dominance") %>% 
           pull(axis_name)) +
    coord_cartesian(ylim = c(0, 100))
  
  print(p)

}
## [1] "Large connected to large"

## [1] "Large unconnected"

Evaporation

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       "water_addition_ml")

\(M_{M}\) vs \(M\)

ecosystem_type_selected = c("Medium unconnected",
                     "Medium connected to medium")

Shannon

response_variable_selected = "shannon"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      0.8   0.206     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     38.5     66.3     -7.2     14.5       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.44  -0.62   0.02   0.66   2.31 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 6e-02    0.24          
##             day         1e-04    0.01     -1.00
##  Residual               7e-02    0.26          
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                             Estimate Std. Error     df t value
## (Intercept)                                    1.321      0.048 58.619    27.7
## ecosystem_typeMedium unconnected               0.013      0.069 43.379     0.2
## scale(day)                                     0.004      0.049 31.165     0.1
## scale(water_addition_ml)                      -0.050      0.053 67.973    -0.9
## scale(baseline)                                0.060      0.032 40.778     1.9
## ecosystem_typeMedium unconnected:scale(day)    0.133      0.074 21.173     1.8
## scale(day):scale(water_addition_ml)            0.022      0.043 69.502     0.5
## scale(day):scale(baseline)                     0.013      0.035 21.012     0.4
##                                             Pr(>|t|)    
## (Intercept)                                   <2e-16 ***
## ecosystem_typeMedium unconnected                0.85    
## scale(day)                                      0.94    
## scale(water_addition_ml)                        0.35    
## scale(baseline)                                 0.07 .  
## ecosystem_typeMedium unconnected:scale(day)     0.09 .  
## scale(day):scale(water_addition_ml)             0.61    
## scale(day):scale(baseline)                      0.71    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Mu scl(d) sc(__) scl(b) e_Mu:( s():(_
## ecsystm_tMu -0.602                                          
## scale(day)   0.009  0.018                                   
## scl(wtr_d_)  0.416 -0.180  0.478                            
## scale(bsln) -0.129  0.176 -0.002 -0.061                     
## ecsys_Mu:()  0.024 -0.108 -0.593 -0.185 -0.016              
## scl(d):(__)  0.593 -0.250  0.163  0.696 -0.093 -0.059       
## scl(dy):s() -0.091  0.023 -0.144 -0.174 -0.114  0.179 -0.169
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.8   0.651     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##     39.4     64.9     -8.7     17.4       64 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.42  -0.53   0.01   0.68   2.25 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e-01    0.32          
##             day         2e-04    0.01     -1.00
##  Residual               7e-02    0.26          
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error     df t value Pr(>|t|)
## (Intercept)                            1.315      0.048 55.798    27.2   <2e-16
## ecosystem_typeMedium unconnected       0.033      0.070 47.495     0.5     0.64
## scale(day)                             0.056      0.042 25.836     1.3     0.20
## scale(water_addition_ml)              -0.034      0.052 67.673    -0.6     0.52
## scale(baseline)                        0.062      0.033 34.979     1.9     0.07
## scale(day):scale(water_addition_ml)    0.025      0.044 68.341     0.6     0.58
## scale(day):scale(baseline)             0.002      0.037 17.944     0.1     0.95
##                                        
## (Intercept)                         ***
## ecosystem_typeMedium unconnected       
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                     .  
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Mu scl(d) sc(__) scl(b) s():(_
## ecsystm_tMu -0.602                                   
## scale(day)  -0.011 -0.060                            
## scl(wtr_d_)  0.427 -0.213  0.444                     
## scale(bsln) -0.128  0.174 -0.014 -0.065              
## scl(d):(__)  0.595 -0.262  0.148  0.692 -0.094       
## scl(dy):s() -0.090  0.041 -0.043 -0.136 -0.172 -0.150
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Biomass

response_variable_selected = "bioarea_mm2_per_ml"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value   evidence
## 1     -5.6   0.008 *** strong
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    222.1    249.9    -99.1    198.1       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.64  -0.49   0.01   0.53   2.38 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 5e-01    0.71          
##             day         2e-04    0.02     -1.00
##  Residual               7e-01    0.84          
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                             Estimate Std. Error     df t value
## (Intercept)                                    2.460      0.196 22.189    12.6
## ecosystem_typeMedium unconnected              -0.973      0.305 14.940    -3.2
## scale(day)                                    -1.094      0.148 52.607    -7.4
## scale(water_addition_ml)                       0.062      0.169 61.036     0.4
## scale(baseline)                               -0.176      0.143 14.378    -1.2
## ecosystem_typeMedium unconnected:scale(day)    0.524      0.218 45.976     2.4
## scale(day):scale(water_addition_ml)           -0.319      0.142 64.436    -2.2
## scale(day):scale(baseline)                    -0.005      0.104 46.664     0.0
##                                             Pr(>|t|)    
## (Intercept)                                    1e-11 ***
## ecosystem_typeMedium unconnected               0.006 ** 
## scale(day)                                     1e-09 ***
## scale(water_addition_ml)                       0.713    
## scale(baseline)                                0.239    
## ecosystem_typeMedium unconnected:scale(day)    0.020 *  
## scale(day):scale(water_addition_ml)            0.028 *  
## scale(day):scale(baseline)                     0.964    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Mu scl(d) sc(__) scl(b) e_Mu:( s():(_
## ecsystm_tMu -0.585                                          
## scale(day)  -0.059  0.055                                   
## scl(wtr_d_)  0.319 -0.118  0.487                            
## scale(bsln)  0.025 -0.069 -0.063 -0.090                     
## ecsys_Mu:()  0.077 -0.157 -0.586 -0.164  0.033              
## scl(d):(__)  0.469 -0.174  0.131  0.682 -0.028 -0.010       
## scl(dy):s() -0.110  0.050  0.047 -0.096 -0.161 -0.085 -0.221
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value    evidence
## 1     -2.2   0.039 ** moderate
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    225.4    250.9   -101.7    203.4       64 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -2.4   -0.5    0.0    0.5    2.5 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 9e-01    0.97          
##             day         8e-04    0.03     -1.00
##  Residual               7e-01    0.86          
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             2.40       0.20 22.69    11.9    3e-11
## ecosystem_typeMedium unconnected       -0.79       0.30 16.98    -2.6     0.02
## scale(day)                             -0.88       0.13 38.38    -6.9    4e-08
## scale(water_addition_ml)                0.14       0.17 59.83     0.8     0.43
## scale(baseline)                        -0.19       0.15 13.47    -1.3     0.22
## scale(day):scale(water_addition_ml)    -0.32       0.15 62.16    -2.2     0.03
## scale(day):scale(baseline)              0.02       0.11 29.60     0.2     0.88
##                                        
## (Intercept)                         ***
## ecosystem_typeMedium unconnected    *  
## scale(day)                          ***
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml) *  
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Mu scl(d) sc(__) scl(b) s():(_
## ecsystm_tMu -0.574                                   
## scale(day)  -0.089 -0.055                            
## scl(wtr_d_)  0.340 -0.165  0.476                     
## scale(bsln)  0.021 -0.061 -0.051 -0.085              
## scl(d):(__)  0.470 -0.181  0.141  0.678 -0.027       
## scl(dy):s() -0.098  0.035 -0.001 -0.103 -0.267 -0.213
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Richness

response_variable_selected = "species_richness"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1     -0.1    0.13     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    303.9    331.7   -140.0    279.9       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -1.91  -0.67   0.01   0.66   2.66 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 9e-01    0.95          
##             day         6e-04    0.02     -1.00
##  Residual               2e+00    1.50          
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                             Estimate Std. Error     df t value
## (Intercept)                                    6e+00      3e-01  2e+01    20.4
## ecosystem_typeMedium unconnected              -1e+00      5e-01  2e+01    -2.1
## scale(day)                                    -2e-01      3e-01  5e+01    -0.8
## scale(water_addition_ml)                      -4e-04      3e-01  6e+01     0.0
## scale(baseline)                                2e-01      2e-01  1e+01     1.1
## ecosystem_typeMedium unconnected:scale(day)    3e-01      4e-01  4e+01     0.7
## scale(day):scale(water_addition_ml)           -1e-01      2e-01  7e+01    -0.5
## scale(day):scale(baseline)                    -4e-02      2e-01  4e+01    -0.2
##                                             Pr(>|t|)    
## (Intercept)                                   <2e-16 ***
## ecosystem_typeMedium unconnected                0.05 *  
## scale(day)                                      0.40    
## scale(water_addition_ml)                        1.00    
## scale(baseline)                                 0.30    
## ecosystem_typeMedium unconnected:scale(day)     0.48    
## scale(day):scale(water_addition_ml)             0.59    
## scale(day):scale(baseline)                      0.81    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Mu scl(d) sc(__) scl(b) e_Mu:( s():(_
## ecsystm_tMu -0.588                                          
## scale(day)  -0.005  0.024                                   
## scl(wtr_d_)  0.361 -0.139  0.488                            
## scale(bsln)  0.024 -0.077 -0.041 -0.066                     
## ecsys_Mu:()  0.045 -0.105 -0.585 -0.163  0.022              
## scl(d):(__)  0.522 -0.199  0.143  0.689 -0.036 -0.018       
## scl(dy):s() -0.087  0.041  0.029 -0.094 -0.108 -0.085 -0.157
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1     -1.6   0.058   * weak
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    302.4    327.9   -140.2    280.4       64 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -1.85  -0.70  -0.05   0.63   2.57 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e+00    1.02          
##             day         7e-04    0.03     -1.00
##  Residual               2e+00    1.50          
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error    df t value Pr(>|t|)
## (Intercept)                             6.23       0.31 25.39    20.3   <2e-16
## ecosystem_typeMedium unconnected       -0.95       0.46 16.38    -2.1     0.06
## scale(day)                             -0.11       0.21 48.90    -0.5     0.60
## scale(water_addition_ml)                0.04       0.29 62.27     0.1     0.90
## scale(baseline)                         0.23       0.22 14.38     1.0     0.31
## scale(day):scale(water_addition_ml)    -0.13       0.25 65.43    -0.5     0.59
## scale(day):scale(baseline)             -0.03       0.18 41.07    -0.2     0.85
##                                        
## (Intercept)                         ***
## ecosystem_typeMedium unconnected    .  
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Mu scl(d) sc(__) scl(b) s():(_
## ecsystm_tMu -0.586                                   
## scale(day)   0.017 -0.048                            
## scl(wtr_d_)  0.372 -0.161  0.490                     
## scale(bsln)  0.023 -0.075 -0.034 -0.063              
## scl(d):(__)  0.521 -0.202  0.161  0.693 -0.035       
## scl(dy):s() -0.082  0.032 -0.025 -0.109 -0.121 -0.158
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Evenness

response_variable_selected = "evenness_pielou"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1     -0.8   0.089   * weak
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    -82.6    -54.8     53.3   -106.6       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.61  -0.72   0.09   0.77   1.97 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e-14    1e-07         
##             day         2e-17    5e-09    -1.00
##  Residual               1e-02    1e-01         
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                             Estimate Std. Error     df t value
## (Intercept)                                    0.758      0.021 75.000    35.4
## ecosystem_typeMedium unconnected               0.067      0.032 75.000     2.1
## scale(day)                                     0.031      0.021 75.000     1.5
## scale(water_addition_ml)                       0.003      0.024 75.000     0.1
## scale(baseline)                               -0.007      0.015 75.000    -0.5
## ecosystem_typeMedium unconnected:scale(day)    0.027      0.032 75.000     0.8
## scale(day):scale(water_addition_ml)            0.043      0.019 75.000     2.2
## scale(day):scale(baseline)                    -0.019      0.015 75.000    -1.3
##                                             Pr(>|t|)    
## (Intercept)                                   <2e-16 ***
## ecosystem_typeMedium unconnected                0.04 *  
## scale(day)                                      0.15    
## scale(water_addition_ml)                        0.92    
## scale(baseline)                                 0.62    
## ecosystem_typeMedium unconnected:scale(day)     0.41    
## scale(day):scale(water_addition_ml)             0.03 *  
## scale(day):scale(baseline)                      0.21    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Mu scl(d) sc(__) scl(b) e_Mu:( s():(_
## ecsystm_tMu -0.621                                          
## scale(day)   0.104 -0.039                                   
## scl(wtr_d_)  0.415 -0.172  0.516                            
## scale(bsln) -0.223  0.352  0.023 -0.018                     
## ecsys_Mu:() -0.040  0.015 -0.621 -0.223 -0.011              
## scl(d):(__)  0.599 -0.261  0.181  0.702 -0.103 -0.070       
## scl(dy):s() -0.059  0.024 -0.266 -0.181 -0.001  0.366 -0.101
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value    evidence
## 1     -2.1   0.042 ** moderate
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##    -83.9    -58.4     53.0   -105.9       64 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##  -2.72  -0.66   0.04   0.77   1.99 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 3e-12    2e-06         
##             day         6e-15    8e-08    -1.00
##  Residual               1e-02    1e-01         
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error     df t value Pr(>|t|)
## (Intercept)                            0.759      0.022 75.000    35.3   <2e-16
## ecosystem_typeMedium unconnected       0.066      0.032 75.000     2.1     0.04
## scale(day)                             0.042      0.017 75.000     2.5     0.01
## scale(water_addition_ml)               0.007      0.023 75.000     0.3     0.77
## scale(baseline)                       -0.007      0.015 75.000    -0.5     0.63
## scale(day):scale(water_addition_ml)    0.044      0.019 75.000     2.3     0.03
## scale(day):scale(baseline)            -0.023      0.014 75.000    -1.7     0.10
##                                        
## (Intercept)                         ***
## ecosystem_typeMedium unconnected    *  
## scale(day)                          *  
## scale(water_addition_ml)               
## scale(baseline)                        
## scale(day):scale(water_addition_ml) *  
## scale(day):scale(baseline)          .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Mu scl(d) sc(__) scl(b) s():(_
## ecsystm_tMu -0.621                                   
## scale(day)   0.101 -0.038                            
## scl(wtr_d_)  0.416 -0.173  0.493                     
## scale(bsln) -0.224  0.352  0.020 -0.021              
## scl(d):(__)  0.598 -0.261  0.176  0.705 -0.104       
## scl(dy):s() -0.048  0.020 -0.053 -0.109  0.003 -0.081
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Median Size

response_variable_selected = "median_body_area_µm2"

We want to know whether the connection influenced this response variable. We first start from plotting how this response variable changed in connected and unconnected ecosystems throughout the experiment through its mean ± 95 confidence interval:

# --- PLOT ORIGINAL DATA --- #

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       response_variable_selected)

 

Following the initial inspection, we proceed to analyse differences among ecosystems. Our first step involves filtering the data to isolate the relevant data for analysis. Specifically, we exclude data points where the response variable couldn’t be computed, as well as time points preceding the initial disturbance and resource flow. Then we plot the data to make sure that what filtered the data in the right way.

# --- FILTER DATA --- #

filtered_data = ds_ecosystems %>%
  filter(time_point %in% time_points_model,
         ecosystem_type %in% ecosystem_type_selected,
         !is.na(!!sym(response_variable_selected)),
         !is.na(!!sym("water_addition_ml")))
# --- PLOT FILTERED DATA --- #

plot.ecosystems.points(filtered_data,
                    ecosystem_type_selected,
                    response_variable_selected) 

 

Then, given that we have gathered measurements from the same ecosystem on multiple occasions, we can develop mixed effect models to examine how the connection influenced this variable. To study the effects of ecosystem connection we compare two models to a null model using ANOVA: a full model and a reduced model. In all models, we treat culture ID as having a random effect on how the slope and intercept of the relationship between response variable and time, with the slope and intercept being correlated (Bates et al. 2015). The full model contains the interaction of connection with time (Response variable ~ connection * day + (day | culture ID)), the reduced model contains the connection but without the interaction with time (Response variable ~ connection + day + (day | culture ID)), and the null model doesn’t contain the connection at all (Response variable ~ day + (day | culture ID)). If any of the two model comparisons is significant, then ecosystem connection had an effect.

# --- ADD BASELINES --- #

baselines = ds_ecosystems %>%
  filter(time_point == time_point_of_baselines) %>%
  select(culture_ID,
         all_of(response_variable_selected)) %>%
  rename(baseline = all_of(response_variable_selected))

filtered_data = filtered_data %>%
  left_join(baselines)
# --- COMPARE FULL, REDUCED, AND NULL MODEL --- #

full_model = lmer(get(response_variable_selected) ~
                    ecosystem_type * scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))

reduced_model = lmer(get(response_variable_selected) ~
                       ecosystem_type + 
                       scale(day) +
                       scale(water_addition_ml) * scale(day) +
                       scale(baseline) * scale(day) +
                       (day | culture_ID),
                     data = filtered_data,
                     REML = FALSE,
                     control = lmerControl(optimizer = "bobyqa"))

null_model = lmer(get(response_variable_selected) ~
                    scale(day) +
                    scale(water_addition_ml) * scale(day) +
                    scale(baseline) * scale(day) +
                    (day | culture_ID),
                  data = filtered_data,
                  REML = FALSE,
                  control = lmerControl(optimizer = "bobyqa"))


Full model vs null model

Full vs null model - ANOVA
# --- FULL VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(full_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      0.4   0.167     none
Full model - summary
# --- FULL MODEL - SHOW SUMMARY --- #

print(summary(full_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type * scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1202.2   1230.0   -589.1   1178.2       63 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -3.9   -0.5    0.0    0.4    3.5 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e+03     31           
##             day         6e+01      8      -1.00
##  Residual               4e+05    611           
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                             Estimate Std. Error   df t value
## (Intercept)                                     3701        115   30    32.2
## ecosystem_typeMedium unconnected                  82        169   18     0.5
## scale(day)                                      -234        106   61    -2.2
## scale(water_addition_ml)                        -161        122   70    -1.3
## scale(baseline)                                  202         78   17     2.6
## ecosystem_typeMedium unconnected:scale(day)      297        156   55     1.9
## scale(day):scale(water_addition_ml)                8        100   72     0.1
## scale(day):scale(baseline)                       115         73   54     1.6
##                                             Pr(>|t|)    
## (Intercept)                                   <2e-16 ***
## ecosystem_typeMedium unconnected                0.63    
## scale(day)                                      0.03 *  
## scale(water_addition_ml)                        0.19    
## scale(baseline)                                 0.02 *  
## ecosystem_typeMedium unconnected:scale(day)     0.06 .  
## scale(day):scale(water_addition_ml)             0.94    
## scale(day):scale(baseline)                      0.12    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Mu scl(d) sc(__) scl(b) e_Mu:( s():(_
## ecsystm_tMu -0.592                                          
## scale(day)   0.142 -0.073                                   
## scl(wtr_d_)  0.402 -0.166  0.492                            
## scale(bsln) -0.041  0.041 -0.001 -0.023                     
## ecsys_Mu:() -0.053  0.073 -0.585 -0.171  0.001              
## scl(d):(__)  0.564 -0.226  0.167  0.708 -0.046 -0.037       
## scl(dy):s()  0.021 -0.006 -0.038 -0.012  0.063  0.041  0.039
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Full model - residual plots
# --- FULL MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, full_model)
qqnorm(resid(full_model))
qqline(resid(full_model))


Reduced vs null model

Reduced vs null model - ANOVA
# --- REDUCED VS NULL MODEL - SHOW MODEL STATS --- #

compute.model.stats(reduced_model,
                    null_model,
                    "mixed_model") %>%
  show.tidy.model.stats(.)
##   deltaAIC p_value evidence
## 1      1.9   0.761     none
Reduced model - summary
# --- REDUCED MODEL - SHOW SUMMARY --- #

print(summary(reduced_model), digits = 1)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: get(response_variable_selected) ~ ecosystem_type + scale(day) +  
##     scale(water_addition_ml) * scale(day) + scale(baseline) *  
##     scale(day) + (day | culture_ID)
##    Data: filtered_data
## Control: lmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1203.6   1229.1   -590.8   1181.6       64 
## 
## Scaled residuals: 
##    Min     1Q Median     3Q    Max 
##   -4.1   -0.4    0.1    0.4    3.6 
## 
## Random effects:
##  Groups     Name        Variance Std.Dev. Corr 
##  culture_ID (Intercept) 1e+04    117           
##             day         1e+02     11      -1.00
##  Residual               4e+05    626           
## Number of obs: 75, groups:  culture_ID, 15
## 
## Fixed effects:
##                                     Estimate Std. Error   df t value Pr(>|t|)
## (Intercept)                             3712        116   35    32.0   <2e-16
## ecosystem_typeMedium unconnected          55        169   24     0.3     0.75
## scale(day)                              -115         89   54    -1.3     0.20
## scale(water_addition_ml)                -120        123   71    -1.0     0.33
## scale(baseline)                          202         78   19     2.6     0.02
## scale(day):scale(water_addition_ml)       13        103   73     0.1     0.90
## scale(day):scale(baseline)               109         75   43     1.4     0.16
##                                        
## (Intercept)                         ***
## ecosystem_typeMedium unconnected       
## scale(day)                             
## scale(water_addition_ml)               
## scale(baseline)                     *  
## scale(day):scale(water_addition_ml)    
## scale(day):scale(baseline)             
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) ecs_Mu scl(d) sc(__) scl(b) s():(_
## ecsystm_tMu -0.591                                   
## scale(day)   0.148 -0.037                            
## scl(wtr_d_)  0.407 -0.158  0.487                     
## scale(bsln) -0.042  0.041 -0.001 -0.024              
## scl(d):(__)  0.573 -0.229  0.181  0.715 -0.047       
## scl(dy):s()  0.023 -0.009 -0.017 -0.005  0.079  0.040
## optimizer (bobyqa) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
Reduced model - residual plots
# --- REDUCED MODEL - SHOW RESIDUAL PLOTS --- #

create.res.vs.fit.ecos(filtered_data, reduced_model)
qqnorm(resid(reduced_model))
qqline(resid(reduced_model))

Populations

for(eco_type_i in 1:length(ecosystem_type_selected)){
  
  print(ecosystem_type_selected[eco_type_i])

  p = ds_ecosystems %>%
  filter(ecosystem_type == ecosystem_type_selected[eco_type_i]) %>%
  group_by(day) %>%
  summarise(Ble = mean(Ble_indiv_per_ml_dominance, na.rm = TRUE),
            Cep = mean(Cep_indiv_per_ml_dominance, na.rm = TRUE),
            Col = mean(Col_indiv_per_ml_dominance, na.rm = TRUE),
            Eug = mean(Eug_indiv_per_ml_dominance, na.rm = TRUE),
            Eup = mean(Eup_indiv_per_ml_dominance, na.rm = TRUE),
            Lox = mean(Lox_indiv_per_ml_dominance, na.rm = TRUE),
            Pau = mean(Pau_indiv_per_ml_dominance, na.rm = TRUE),
            Pca = mean(Pca_indiv_per_ml_dominance, na.rm = TRUE),
            Spi = mean(Spi_indiv_per_ml_dominance, na.rm = TRUE),
            Spi_te = mean(Spi_te_indiv_per_ml_dominance, na.rm = TRUE),
            Tet = mean(Tet_indiv_per_ml_dominance, na.rm = TRUE)) %>%
    pivot_longer(Ble:Tet, names_to = "species", values_to = "species_indiv_per_ml") %>%
    ggplot(aes(x = day,
               y = species_indiv_per_ml,
               group = interaction(day, species),
               color = species)) +
  geom_point(position = position_dodge(dodging),
             size = treatment_points_size) +
  geom_line(aes(group = species),
            position = position_dodge(dodging),
            linewidth = treatment_lines_linewidth) + 
    labs(x = axis_names %>% 
           filter(variable == "day") %>% 
           pull(axis_name),
         y = axis_names %>% 
           filter(variable == "dominance") %>% 
           pull(axis_name)) +
    coord_cartesian(ylim = c(0, 100))
  
  print(p)

}
## [1] "Medium unconnected"

## [1] "Medium connected to medium"

Evaporation

plot.ecosystems.points(ds_ecosystems,
                       ecosystem_type_selected,
                       "water_addition_ml")

Results

Meta-ecosystem diversity & function

We want here to plot the final paper version of the biodiversity and productivity of meta-ecosystems. We need to plot it again instead of using the plots we used in the analysis because we want to change the size of the plot.

# Define meta-ecosystems you want to plot.

metaecosystem_type_selected = c("Medium-Medium",
                                "Small-Large")
# Write function to plot a response variable. Afterwards you can use this function to plot alpha, beta, gamma diversity, and biomass.

plot.single.plot = function(response_variable_selected){
  
  ds_metaecosystems %>%
    filter(metaecosystem_type %in% metaecosystem_type_selected,
           !is.na(!!sym(response_variable_selected))) %>%
    summarySE(measurevar = response_variable_selected,
              groupvars = c("day", "metaecosystem_type", "connection")) %>%
    ggplot(aes(x = day,
               y = get(response_variable_selected),
               group = interaction(day, metaecosystem_type, connection),
               color = metaecosystem_type,
               linetype = connection)) +
    geom_point(stat = "summary",
               fun = "mean",
               position = position_dodge(dodging),
               size = treatment_points_size) +
    geom_line(stat = "summary",
              fun = "mean",
              aes(group = interaction(metaecosystem_type, connection)),
              position = position_dodge(dodging),
              linewidth = treatment_lines_linewidth) +
    geom_errorbar(aes(ymax = get(response_variable_selected) + ci,
                      ymin = get(response_variable_selected) - ci),
                  width = width_errorbar,
                  position = position_dodge(dodging)) +
    labs(x = axis_names$axis_name[axis_names$variable == "day"],
         y = axis_names$axis_name[axis_names$variable == response_variable_selected],
         color = "") +
    scale_color_manual(values = treatment_colours) +
    scale_linetype_manual(values = treatment_linetype) +
    geom_vline(xintercept = resource_flow_days,
               linetype = resource_flow_line_type,
               color = resource_flow_line_colour,
               linewidth = resource_flow_line_width) +
    theme_bw() +
    theme(panel.grid.major = element_blank(),
          panel.grid.minor = element_blank(),
          legend.position = legend_position,
          legend.key.width = unit(legend_width_cm, "cm")) +
    guides(color = guide_legend(title = NULL,
                                nrow = 2),
           linetype = guide_legend(title = NULL,
                                   nrow = 2)) +
    theme(plot.margin = unit(c(ggarrange_margin_left,
                               ggarrange_margin_right,
                               ggarrange_margin_bottom,
                               ggarrange_margin_left),
                             "cm")) +
    geom_rect(xmin = grey_background_xmin, 
              xmax = grey_background_xmax,
              ymin = grey_background_ymin, 
              ymax = grey_background_ymax, 
              fill = grey_background_fill, 
              alpha = grey_background_alpha,
              color = grey_background_color)
}
# Combine plots of alpha, beta, gamma biodiversity and biomass.

p_combined = ggarrange(plot.single.plot("mean_shannon") +
                         rremove("xlab") +
                         theme(axis.text.x = element_blank(),
                               axis.ticks.x = element_blank()) +
                         font("legend.text", size = paper_labels_size) +
                         font("ylab", size = paper_labels_size),
                       plot.single.plot("bray_curtis") +
                         rremove("xlab") +
                         theme(axis.text.x = element_blank(),
                               axis.ticks.x = element_blank()) +
                         font("legend.text", 
                              size = paper_labels_size) +
                         font("ylab", 
                              size = paper_labels_size),
                       plot.single.plot("metaecosystem_richness") +
                         rremove("xlab") +
                         theme(axis.text.x = element_blank(),
                               axis.ticks.x = element_blank()) +
                         font("legend.text", 
                              size = paper_labels_size) +
                         font("ylab", 
                              size = paper_labels_size),
                       plot.single.plot("total_metaecosystem_bioarea_mm2") +
                         font("legend.text", 
                              size = paper_labels_size) +
                         font("xlab", 
                              size = paper_labels_size) +
                         font("ylab", 
                              size = paper_labels_size) +
                         scale_x_continuous(breaks = unique(ds_metaecosystems$day)),
                       heights = c(0.8, 0.8, 0.8, 1),
                       nrow = 4,
                       common.legend = TRUE,
                       align = "v",
                       labels = c("(a)", "(b)", "(c)", "(d)"),
                       label.x = 0.1,
                       label.y = 0.8) %>%
  print()

## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's linetype values.

Ecosystem diversity & function

We want here to plot the final paper version of the biodiversity and productivity of the small and large ecosystems. We need to plot it again instead of using the plots we used in the analysis because we want to have the underscores in the legend. We don’t use underscores in the analysis because we can’t easily input them from a level name vector.

# Define ecosystems you want to plot.

ecosystem_type_selected = c("Small connected to large",
                            "Small connected to small",
                            "Small unconnected",
                            "Large connected to small",
                            "Large connected to large",
                            "Large unconnected")
# Construct function to plot how the response variable (biomass or Shannon) of small and large ecosystems changes across time.

plot.single.plot = function(response_variable_selected){
  
  ds_ecosystems %>%
    filter(ecosystem_type %in% ecosystem_type_selected,
           !is.na(!!sym(response_variable_selected))) %>%
    summarySE(measurevar = response_variable_selected,
              groupvars = c("day", "time_point", "ecosystem_type", "ecosystem_size", "connection")) %>%
    ggplot(aes(x = day,
               y = get(response_variable_selected),
               group = interaction(day, ecosystem_type),
               color = ecosystem_type,
               linetype = ecosystem_type)) +
    geom_point(stat = "summary",
               fun = "mean",
               position = position_dodge(dodging),
               size = treatment_points_size) +
    geom_line(stat = "summary",
              fun = "mean",
              aes(group = ecosystem_type),
              position = position_dodge(dodging),
              linewidth = treatment_lines_linewidth) +
    geom_errorbar(aes(ymax = get(response_variable_selected) + ci,
                      ymin = get(response_variable_selected) - ci),
                  width = width_errorbar,
                  position = position_dodge(dodging)) +
    labs(x = axis_names$axis_name[axis_names$variable == "day"],
         y = axis_names$axis_name[axis_names$variable == response_variable_selected],
         color = "") +
    scale_color_manual(values = c("#993404",
                                  "#993404",
                                  "#993404",
                                  "#3182bd",
                                  "#3182bd",
                                  "#3182bd"),
                       label = expression(S[L], 
                                          S[S],
                                          S,
                                          L[S], 
                                          L[L], 
                                          L)) +
    scale_linetype_manual(values = c("solid",
                                     "dashed",
                                     "dotted",
                                     "solid",
                                     "dashed",
                                     "dotted"),
                          label = expression(S[L], 
                                             S[S],
                                             S,
                                             L[S], 
                                             L[L], 
                                             L)) +
    geom_vline(xintercept = resource_flow_days,
               linetype = resource_flow_line_type,
               color = resource_flow_line_colour,
               linewidth = resource_flow_line_width) +
    geom_hline(yintercept = 0,
               color = zero_line_colour,
               linetype = zero_line_line_type,
               linewidth = zero_line_line_width) +
    theme_bw() +
    theme(panel.grid.major = element_blank(),
          panel.grid.minor = element_blank(),
          legend.position = legend_position,
          legend.key.width = unit(legend_width_cm, "cm")) +
    guides(color = guide_legend(title = NULL,
                                nrow = 3),
           linetype = guide_legend(title = NULL,
                                   nrow = 3)) + 
    geom_rect(xmin = grey_background_xmin, 
              xmax = grey_background_xmax,
              ymin = grey_background_ymin, 
              ymax = grey_background_ymax, 
              fill = grey_background_fill, 
              alpha = grey_background_alpha,
              color = grey_background_color)
}
# Combine plots

p_combined = ggarrange(plot.single.plot("shannon") +
                         rremove("xlab") +
                         theme(axis.text.x = element_blank(),
                               axis.ticks.x = element_blank()) +
                         font("legend.text", 
                              size = paper_labels_size) +
                         font("ylab", 
                              size = paper_labels_size),
                       plot.single.plot("bioarea_mm2_per_ml") +
                         font("legend.text", 
                              size = paper_labels_size) +
                         font("xlab", 
                              size = paper_labels_size) +
                         font("ylab", 
                              size = paper_labels_size) +
                         scale_x_continuous(breaks = unique(ds_ecosystems$day)),
                       heights = c(0.8, 0.8, 1),
                       nrow = 2,
                       align = "v",
                       labels = c("(a)", "(b)"),
                       label.x = 0.1,
                       label.y = 0.8,
                       common.legend = TRUE) %>%
  print()

We want here to plot the final paper version of the biodiversity and productivity of the medium ecosystems. We need to plot it again instead of using the plots we used in the analysis because we want to have the underscores in the legend. We don’t use underscores in the analysis because we can’t easily input them from a level name vector.

# Define ecosystems you want to plot.

ecosystem_type_selected = c("Medium connected to medium",
                         "Medium unconnected")
# Construct function to plot how the response variable (biomass or Shannon) of small and large ecosystems changes across time.

plot.single.plot = function(response_variable_selected){
  
  ds_ecosystems %>%
    filter(ecosystem_type %in% ecosystem_type_selected,
           !is.na(!!sym(response_variable_selected))) %>%
    summarySE(measurevar = response_variable_selected,
              groupvars = c("day", "time_point", "ecosystem_type", "ecosystem_size", "connection")) %>%
    ggplot(aes(x = day,
               y = get(response_variable_selected),
               group = interaction(day, ecosystem_type),
               color = ecosystem_type,
               linetype = ecosystem_type)) +
    geom_point(stat = "summary",
               fun = "mean",
               position = position_dodge(dodging),
               size = treatment_points_size) +
    geom_line(stat = "summary",
              fun = "mean",
              aes(group = ecosystem_type),
              position = position_dodge(dodging),
              linewidth = treatment_lines_linewidth) +
    geom_errorbar(aes(ymax = get(response_variable_selected) + ci,
                      ymin = get(response_variable_selected) - ci),
                  width = width_errorbar,
                  position = position_dodge(dodging)) +
    labs(x = axis_names$axis_name[axis_names$variable == "day"],
         y = axis_names$axis_name[axis_names$variable == response_variable_selected],
         color = "") +
    scale_color_manual(values = c("#d95f0e",
                                  "#d95f0e"),
                       label = expression(M[M], 
                                          M)) +
    scale_linetype_manual(values = c("dashed",
                                     "dotted"),
                          label = expression(M[M], 
                                             M)) +
    geom_vline(xintercept = resource_flow_days,
               linetype = resource_flow_line_type,
               color = resource_flow_line_colour,
               linewidth = resource_flow_line_width) +
    geom_hline(yintercept = 0,
               color = zero_line_colour,
               linetype = zero_line_line_type,
               linewidth = zero_line_line_width) +
    theme_bw() +
    theme(panel.grid.major = element_blank(),
          panel.grid.minor = element_blank(),
          legend.position = legend_position,
          legend.key.width = unit(legend_width_cm, "cm")) +
    guides(color = guide_legend(title = NULL,
                                nrow = 3),
           linetype = guide_legend(title = NULL,
                                   nrow = 3)) + 
    geom_rect(xmin = grey_background_xmin, 
              xmax = grey_background_xmax,
              ymin = grey_background_ymin, 
              ymax = grey_background_ymax, 
              fill = grey_background_fill, 
              alpha = grey_background_alpha,
              color = grey_background_color)
}
# Combine plots

p_combined = ggarrange(plot.single.plot("shannon") +
                         rremove("xlab") +
                         theme(axis.text.x = element_blank(),
                               axis.ticks.x = element_blank()) +
                         font("legend.text", 
                              size = paper_labels_size) +
                         font("ylab", 
                              size = paper_labels_size),
                       plot.single.plot("bioarea_mm2_per_ml") +
                         font("legend.text", 
                              size = paper_labels_size) +
                         font("xlab", 
                              size = paper_labels_size) +
                         font("ylab", 
                              size = paper_labels_size) +
                         scale_x_continuous(breaks = unique(ds_ecosystems$day)),
                       heights = c(0.8, 0.8, 1),
                       nrow = 2,
                       align = "v",
                       labels = c("(a)", "(b)"),
                       label.x = 0.1,
                       label.y = 0.8,
                       common.legend = TRUE) %>%
  print()

Ecosystem autotrophic/heterotrophic ratio

We want here to plot the final paper version of the ratio between autotrophic and heterotrophic biomass in small, medium, and large unconnected ecosystems. We need to plot it again instead of using the plots we used in the analysis because we want to have S, M, and L in the legend.

# Define ecosystems and response variable you want to plot.

ecosystem_type_input = c("S",
                     "M",
                     "L")

response_variable = "auto_hetero_ratio"
# Construct plot

p = ds_ecosystems %>%
  
  # Manipulate
  
  mutate(ecosystem_type = case_when(ecosystem_type == "Small unconnected" ~ "S",
                                ecosystem_type == "Medium unconnected" ~ "M",
                                ecosystem_type == "Large unconnected" ~ "L")) %>%
  filter(ecosystem_type %in% ecosystem_type_input,
         !is.na(!!sym(response_variable))) %>%
  summarySE(measurevar = response_variable,
            groupvars = c("day", "ecosystem_type", "ecosystem_size", "connection")) %>%
  
  # Create plot
  
  ggplot(aes(x = day,
             y = get(response_variable),
             group = interaction(day, ecosystem_type),
             color = ecosystem_type)) +
  
  # Points
  
  geom_point(stat = "summary",
             fun = "mean",
             position = position_dodge(dodging),
             size = treatment_points_size) +
  geom_errorbar(aes(ymax = get(response_variable) + ci,
                    ymin = get(response_variable) - ci),
                width = width_errorbar,
                position = position_dodge(dodging)) +
  
  # Lines
  
  geom_line(stat = "summary",
            fun = "mean",
            aes(group = ecosystem_type),
            position = position_dodge(dodging),
            linewidth = treatment_lines_linewidth) +
  
  # Axes and legend
  
  labs(x = axis_names$axis_name[axis_names$variable == "day"],
       y = axis_names$axis_name[axis_names$variable == response_variable],
       color = "") +
  scale_x_continuous(breaks = unique(ds_ecosystems$day)) +
  guides(color = guide_legend(title = NULL,
                              nrow = 1),
         linetype = guide_legend(title = NULL,
                                 nrow = 1)) +
  scale_color_manual(values = c("#000000",
                                "#737373",
                                "#bdbdbd")) +
  
  # Extra graphic elements
  
  theme_bw() +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position = legend_position,
        legend.key.width = unit(legend_width_cm, "cm"),
        axis.title.x = element_text(size = paper_labels_size),
        axis.title.y = element_text(size = paper_labels_size),
        legend.text = element_text(size = paper_labels_size)) +
  geom_rect(xmin = grey_background_xmin, 
            xmax = grey_background_xmax,
            ymin = grey_background_ymin, 
            ymax = grey_background_ymax, 
            fill = grey_background_fill, 
            alpha = grey_background_alpha,
            color = grey_background_color) + 
  geom_hline(yintercept = 0,
             color = zero_line_colour,
             linetype = zero_line_line_type,
             linewidth = zero_line_line_width) +
  
  geom_vline(xintercept = resource_flow_days,
             linetype = resource_flow_line_type,
             color = resource_flow_line_colour,
             linewidth = resource_flow_line_width)

p

Evaporation

During the experiment we noticed that microwaving ecosystem sub-samples for three minutes to create disturbance caused the evaporation of the ecosystems. However, we don’t know exactly how much evaporated and how much we should refill the ecosystems to bring them back to the original volume. Therefore, here I quantify the evaporation of 5.75 and 6.75 ml of deionised water, which represent low and high disturbance, respectively. For each disturbance level, I microwaved 15 tubes of that disturbance level for three minutes and measured their evaporation. To do so, I weighed the water before the microwaving (weigh tubes, add water, reweigh tubes) and after it (weigh Becker, pour water into it, reweigh Becker).

evaporation.test = read.csv(here("1_experiment", "evaporation_test","evaporation_test_initial.csv"), header = TRUE)

evaporation.test %>%
  ggplot(aes (x = as.character(water_pipetted),
                y = weight_water_evaporated,
                group = interaction(water_pipetted, as.character(rack)),
                fill = as.character(rack))) +
  geom_boxplot(width = boxplot_width) +
  labs(x = "Water volume (ml)" , 
       y = "Evaporation (g)", 
       fill = "Rack replicate")

Furthermore, during the experiment we noticed that microwaving five 6.75 ml ecosystems sub-samples with ten empty tubes for three minutes to create disturbance caused the evaporation of the sub-samples more than if they were with other sub-samples. However, we don’t know exactly how much evaporated and how much we should refill the ecosystems to bring them back to the original volume. Therefore, here I quantify the evaporation of five 6.75 ml sub-samples with ten empty or filled falcon tubes. The weighting was conducted as above.

evaporation.test = read.csv(here("1_experiment", "evaporation_test", "evaporation_test_fill_nofill.csv"), header = TRUE)

evaporation.test %>%
  ggplot(aes (x = all_tubes_water,
              y = weight_water_evaporated)) +
  geom_boxplot(width = boxplot_width) +
  labs(x = "Water in the other 10 tubes" , 
  y = "Evaporation (g)")

Analysis scripts

Video analysis

To analyse the videos I took of the ecosystems, I used the package BEMOVI. For this, I had to use the powerful computer. Below is the code utilised for video analysis on the powerful computer.

# Clear workspace
rm(list = ls())

# Set working directory
setwd("/media/mendel-himself/ID_061_Ema2/PatchSizePilot/training")

# Load required libraries
# library(devtools)
# install_github("femoerman/bemovi", ref="master")
library(bemovi)
library(parallel)
library(doParallel)
library(foreach)

# Define memory allocation parameters (in MB)
memory.alloc <- 240000           # Total memory allocated
memory.per.identifier <- 40000   # Memory per identifier
memory.per.linker <- 5000        # Memory per linker
memory.per.overlay <- 60000      # Memory per overlay

# Set paths for tools and particle linker
tools.path <- "/home/mendel-himself/bemovi_tools/" # Path to tools folder
to.particlelinker <- tools.path

# Set directories and file names
to.data <- paste(getwd(), "/", sep = "")
video.description.folder <- "0_video_description/"
video.description.file <- "video_description.txt"
raw.video.folder <- "1_raw/"
raw.avi.folder <- "1a_raw_avi/"
metadata.folder <- "1b_raw_meta/"
particle.data.folder <- "2_particle_data/"
trajectory.data.folder <- "3_trajectory_data/"
temp.overlay.folder <- "4a_temp_overlays/"
overlay.folder <- "4_overlays/"
merged.data.folder <- "5_merged_data/"
ijmacs.folder <- "ijmacs/"

######################################################################
# VIDEO PARAMETERS

# Define video parameters
fps <- 25                  # Video frame rate (frames per second)
total_frames <- 125        # Total length of video (frames)
width <- 2048              # Video width (pixels)
height <- 2048             # Video height (pixels)
measured_volume <- 34.4    # Measured volume (microliters) for Leica M205 C with 1.6 fold magnification, sample height 0.5 mm and Hamamatsu Orca Flash 4
pixel_to_scale <- 4.05     # Size of a pixel (micrometers) for Leica M205 C with 1.6 fold magnification, sample height 0.5 mm and Hamamatsu Orca Flash 4
video.format <- "cxd"      # Video file format (avi, cxd, mov, tiff)
difference.lag <- 10       # Difference lag
thresholds <- c(13, 255)   # Threshold values of pixel intensity (considered a measure of pixel "whiteness") for determining if a pixel belongs to an individual rather than the background

######################################################################
# FILTERING PARAMETERS
# optimized for Perfex Pro 10 stereomicrocope with Perfex SC38800 (IDS UI-3880LE-M-GL) camera
# tested stereomicroscopes: Perfex Pro 10, Nikon SMZ1500, Leica M205 C
# tested cameras: Perfex SC38800, Canon 5D Mark III, Hamamatsu Orca Flash 4
# tested species: Tet, Col, Pau, Pca, Eug, Chi, Ble, Ceph, Lox, Spi

particle_min_size <- 10           # Minimum particle size (pixels)
particle_max_size <- 1000         # Maximum particle size (pixels)
trajectory_link_range <- 3        # Number of adjacent frames for linking particles
trajectory_displacement <- 16     # Maximum displacement of a particle between frames

# Filtering criteria
filter_min_net_disp <- 25         # Minimum net displacement (µm)
filter_min_duration <- 1          # Minimum duration (s)
filter_detection_freq <- 0.1      # Minimum detection frequency (1/s)
filter_median_step_length <- 3    # Minimum median step length (µm)

######################################################################
# VIDEO ANALYSIS

# Check if all tools are installed and set permissions
check_tools_folder(tools.path)
system(paste0("chmod a+x ", tools.path, "bftools/bf.sh"))
system(paste0("chmod a+x ", tools.path, "bftools/bfconvert"))
system(paste0("chmod a+x ", tools.path, "bftools/showinf"))

# Convert video files to compressed avi format
convert_to_avi(to.data,
               raw.video.folder,
               raw.avi.folder,
               metadata.folder,
               tools.path,
               fps,
               video.format)


# Uncomment the following lines for testing
# check_video_file_names(to.data, raw.avi.folder, video.description.folder, video.description.file)
# check_threshold_values(to.data, raw.avi.folder, ijmacs.folder, 2, difference.lag, thresholds, tools.path, memory.alloc)

# Identify particles in the video
locate_and_measure_particles(to.data,
                             raw.avi.folder,
                             particle.data.folder,
                             difference.lag,
                             min_size = particle_min_size,
                             max_size = particle_max_size,
                             thresholds = thresholds,
                             tools.path,
                             memory = memory.alloc,
                             memory.per.identifier = memory.per.identifier,
                             max.cores = detectCores() - 1)

# Link particles across frames to form trajectories
link_particles(to.data,
               particle.data.folder,
               trajectory.data.folder,
               linkrange = trajectory_link_range,
               disp = trajectory_displacement,
               start_vid = 1,
               memory = memory.alloc,
               memory_per_linkerProcess = memory.per.linker,
               raw.avi.folder,
               max.cores = detectCores() - 1,
               max_time = 1)

# Merge video description file with particle data
merge_data(to.data,
           particle.data.folder,
           trajectory.data.folder,
           video.description.folder,
           video.description.file,
           merged.data.folder)

# Load the merged data
load(paste0(to.data, merged.data.folder, "Master.RData"))

# Filter trajectory data based on defined criteria
trajectory.data.filtered <- filter_data(trajectory.data,
                                        filter_min_net_disp,
                                        filter_min_duration,
                                        filter_detection_freq,
                                        filter_median_step_length)

# Summarize trajectory data to individual-based data
morph_mvt <- summarize_trajectories(trajectory.data.filtered,
                                    calculate.median = F,
                                    write = T,
                                    to.data,
                                    merged.data.folder)

# Summarize sample level data
summarize_populations(trajectory.data.filtered,
                      morph_mvt,
                      write = T,
                      to.data,
                      merged.data.folder,
                      video.description.folder,
                      video.description.file,
                      total_frames)

# Create overlays for validation
create.subtitle.overlays(to.data,
                         traj.data = trajectory.data.filtered,
                         raw.video.folder,
                         raw.avi.folder,
                         temp.overlay.folder,
                         overlay.folder,
                         fps,
                         vid.length = total_frames / fps,
                         width,
                         height,
                         tools.path = tools.path,
                         overlay.type = "number",
                         video.format)

# Create overlays (old method)
create_overlays(traj.data = trajectory.data.filtered,
                to.data = to.data,
                merged.data.folder = merged.data.folder,
                raw.video.folder = raw.avi.folder,
                temp.overlay.folder = "4a_temp_overlays_old/",
                overlay.folder = "4_overlays_old/",
                width = width,
                height = height,
                difference.lag = difference.lag,
                type = "traj",
                predict_spec = F,
                contrast.enhancement = 1,
                IJ.path = "/home/mendel-himself/bemovi_tools",
                memory = memory.alloc,
                max.cores = detectCores() - 1,
                memory.per.overlay = memory.per.overlay)

Species identification

To avoid transferring all the data from the powerful computer, I performed species identification on that system and subsequently imported the results into the Rstudio folder on my personal computer. Below is the code utilised for species identification on the powerful computer.

# Clear the workspace
rm(list = ls())

# Uncomment and install required packages if not already installed
#install.packages("e1071",dependencies = T)
#install.packages("devtools",dependencies = T)
#install_github("pennekampster/bemovi", ref="master")
#library(devtools)

# Load required libraries
library(bemovi)
library(e1071)
library("here")
library("tidyverse")

# Define time points in the experiment
time_points_in_experiment = c("t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7")

# Loop through each time point in the experiment
for (time_point in time_points_in_experiment) {
  
  # Define folder names and paths
  video.description.folder = "0_video_description/"
  video.description.file = "video_description.txt"
  merged.data.folder = "5_merged_data/"
  monocultures_folder_path = here("biomass_analysis", "training", "")
  mixed_cultures_folder_path = here("biomass_analysis", time_point, "")
  
  #Parameters used in the video analysis script
  fps = 25
  nsv = 5
  measured_volume = 34.4
  pixel_to_scale = 4.05
  filter_min_net_disp = 25
  filter_min_duration = 1
  filter_detection_freq = 0.1
  filter_median_step_length = 3
  
  # Load master dataset of mono-cultures
  load(paste0(monocultures_folder_path, merged.data.folder, "Master.RData"))
  trajectory.data_monocultures = trajectory.data
  rm(trajectory.data)
  
  # Filter the master data of mono-cultures using the same parameters as in the video analysis script
  trajectory.data_monocultures.filtered = filter_data(trajectory.data_monocultures,
                                                      filter_min_net_disp,
                                                      filter_min_duration,
                                                      filter_detection_freq,
                                                      filter_median_step_length)
  
  # Summarize trajectory data to individual-based data
  morph_mvt = summarize_trajectories(data = trajectory.data_monocultures.filtered,
                                     calculate.median = FALSE,
                                     write = TRUE,
                                     to.data = monocultures_folder_path,
                                     merged.data.folder = merged.data.folder) %>%
    mutate(comment = NULL)
  
  # Prepare training data by removing incomplete cases
  training_data = morph_mvt[complete.cases(morph_mvt), ]
  
  # Train SVM model on the training data
  svm1 = svm(
    factor(species) ~
      mean_grey +
      sd_grey +
      mean_area +
      sd_area +
      mean_perimeter +
      mean_turning +
      sd_turning +
      sd_perimeter +
      mean_major +
      sd_major +
      mean_minor +
      sd_minor +
      mean_ar +
      sd_ar +
      duration +
      max_net  +
      net_disp +
      net_speed +
      gross_disp +
      max_step +
      min_step +
      sd_step +
      sd_gross_speed +
      max_gross_speed +
      min_gross_speed ,
    data = training_data,
    probability = T,
    na.action = na.pass)
  
  # Generate and print confusion matrix
  confusion.matrix = table(svm1$fitted, training_data$species)
  confusion.matrix.nd = confusion.matrix
  diag(confusion.matrix.nd) = 0
  svm1$confusion = cbind(confusion.matrix,
                         class.error = rowSums(confusion.matrix.nd) / rowSums(confusion.matrix))
  
  print(paste("Confusion matrix of time point", time_point))
  print(svm1$confusion)
  
  # Extract unique species names
  species.names = unique(trajectory.data_monocultures$species)
  
  # Load mixed cultures dataset
  load(paste0(mixed_cultures_folder_path, merged.data.folder, "Master.RData"))
  trajectory.data_mixed = trajectory.data
  rm(trajectory.data)
  
  # Filter mixed cultures data using the same parameters
  trajectory.data_mixed.filtered = filter_data(trajectory.data_mixed,
                                               filter_min_net_disp,
                                               filter_min_duration,
                                               filter_detection_freq,
                                               filter_median_step_length)
  
  # Summarize trajectory data to individual-based data
  morph_mvt = summarize_trajectories(data = trajectory.data_mixed.filtered,
                                     calculate.median = FALSE,
                                     write = TRUE,
                                     to.data = mixed_cultures_folder_path,
                                     merged.data.folder = merged.data.folder)[, which(colnames(morph_mvt) != "Col_manual")] %>%
    mutate(comment = NULL)
  
  # Prepare data for prediction by removing incomplete cases
  data.to.predict = morph_mvt[complete.cases(morph_mvt),]
  
  # Predict species using the trained SVM model
  p.id = predict(object = svm1, data.to.predict, type = "response")
  data.to.predict$predicted_species = as.character(p.id)
  
  # Summarize population data
  pop.data = summarize_populations(traj.data = trajectory.data_monocultures.filtered,
                                   sum.data = morph_mvt,
                                   write = TRUE,
                                   to.data = mixed_cultures_folder_path,
                                   merged.data.folder = merged.data.folder,
                                   video.description.folder = video.description.folder,
                                   video.description.file = video.description.file,
                                   total_frame = fps * nsv)
  
  # Function to calculate species density
  species.density = function(sample_output,
                             indiv_predicted,
                             species_names,
                             total_frames,
                             mv = measured_volume) {
    samples = unique(indiv_predicted$file)
    
    sp.dens = matrix(0,
                     nrow(sample_output),
                     length(species_names))
    
    colnames(sp.dens) = species_names
    
    for (i in 1:length(samples)) {
      indiv = subset(indiv_predicted, file == samples[i])
      
      spec = unique(indiv$predicted_species)
      
      for (j in 1:length(spec)) {
        all.indiv.sp = subset(indiv,
                              predicted_species == spec[j])
        
        dens = sum(all.indiv.sp$N_frames) / total_frames / mv
        sp.dens[which(sample_output$file == as.character(samples[i])), which(species_names == spec[j])] = dens
      }
    }
    
    return(cbind(sample_output, sp.dens))
    
  }
  
  # Calculate species density for the current time point
  output = species.density(pop.data,
                           data.to.predict,
                           species.names,
                           total_frames = fps * nsv,
                           mv = measured_volume)
  
  # Save the species density results to a CSV file
  file_name = paste0("species_ID_", time_point, ".csv")
  write.csv(output, here("biomass_analysis", "species_ID_results", file_name))
  rm(output)
  
}

Other

Running time

## Time difference of 1.9 mins

Disturbance input

Check that disturbance_global_selected is what you set:

print(paste0("Disturbance = ", disturbance_global_selected))
## [1] "Disturbance = low"

Useful code

If you want to change a certain part of the code using the following code in Unix:

#Rmd script
cd /Users/Ema/Documents/Github/PatchSize/3_r_files
sed -i '' 's/old_string/new_string/g' *.Rmd

#R script
cd /Users/ema/Documents/GitHub/PatchSize/3_r_files/functions
sed -i '' 's/old_string/new_string/g' *.R

you want to share a dataset and get a reproducible object, use the following R code:

dput()

Crashed cultures

The only type of ecosystem where all cultures crashed was small connected to small at high disturbance.

R version

R.version.string
## [1] "R version 4.3.2 (2023-10-31)"

R package versions

The R packages we used with their version are as follows:

sessionInfo()
## R version 4.3.2 (2023-10-31)
## Platform: aarch64-apple-darwin20 (64-bit)
## Running under: macOS Sonoma 14.2.1
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRblas.0.dylib 
## LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.0
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## time zone: Europe/Zurich
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices datasets  utils     methods   base     
## 
## other attached packages:
##  [1] conflicted_1.2.0    broom.mixed_0.2.9.5 emmeans_1.10.4     
##  [4] combinat_0.0-8      Rmisc_1.5.1         betapart_1.6       
##  [7] vegan_2.6-6.1       lattice_0.22-6      permute_0.9-7      
## [10] glmmTMB_1.1.10      lmerTest_3.1-3      lme4_1.1-35.4      
## [13] Matrix_1.6-5        GGally_2.2.1        gridExtra_2.3      
## [16] plotly_4.10.4       ggpubr_0.6.0        lubridate_1.9.3    
## [19] forcats_1.0.0       stringr_1.5.1       dplyr_1.1.4        
## [22] purrr_1.0.2         readr_2.1.5         tidyr_1.3.1        
## [25] tibble_3.2.1        ggplot2_3.5.1       tidyverse_2.0.0    
## [28] plyr_1.8.9          renv_1.0.7.9000     testthat_3.2.1.1   
## [31] here_1.0.1         
## 
## loaded via a namespace (and not attached):
##   [1] RColorBrewer_1.1-3  rstudioapi_0.16.0   jsonlite_1.8.8     
##   [4] magrittr_2.0.3      estimability_1.5.1  farver_2.1.2       
##   [7] nloptr_2.1.1        rmarkdown_2.27      vctrs_0.6.5        
##  [10] memoise_2.0.1       minqa_1.2.7         rstatix_0.7.2      
##  [13] htmltools_0.5.8.1   itertools_0.1-3     broom_1.0.6        
##  [16] pracma_2.4.4        sass_0.4.9          parallelly_1.38.0  
##  [19] bslib_0.7.0         htmlwidgets_1.6.4   desc_1.4.3         
##  [22] cachem_1.1.0        TMB_1.9.15          lifecycle_1.0.4    
##  [25] minpack.lm_1.2-4    iterators_1.0.14    pkgconfig_2.0.3    
##  [28] optimx_2023-10.21   R6_2.5.1            fastmap_1.2.0      
##  [31] rbibutils_2.2.16    future_1.34.0       magic_1.6-1        
##  [34] digest_0.6.36       numDeriv_2016.8-1.1 colorspace_2.1-0   
##  [37] furrr_0.3.1         rprojroot_2.0.4     pkgload_1.3.4      
##  [40] crosstalk_1.2.1     labeling_0.4.3      fansi_1.0.6        
##  [43] timechange_0.3.0    httr_1.4.7          abind_1.4-5        
##  [46] mgcv_1.9-0          compiler_4.3.2      withr_3.0.0        
##  [49] backports_1.5.0     carData_3.0-5       ggstats_0.6.0      
##  [52] highr_0.11          ggsignif_0.6.4      MASS_7.3-60        
##  [55] tools_4.3.2         ape_5.8             glue_1.7.0         
##  [58] rcdd_1.6            nlme_3.1-163        grid_4.3.2         
##  [61] cluster_2.1.4       generics_0.1.3      snow_0.4-4         
##  [64] gtable_0.3.5        tzdb_0.4.0          data.table_1.15.4  
##  [67] hms_1.1.3           car_3.1-2           utf8_1.2.4         
##  [70] foreach_1.5.2       pillar_1.9.0        splines_4.3.2      
##  [73] tidyselect_1.2.1    knitr_1.47          reformulas_0.3.0   
##  [76] xfun_0.45           brio_1.1.5          stringi_1.8.4      
##  [79] lazyeval_0.2.2      yaml_2.3.8          boot_1.3-30        
##  [82] evaluate_0.24.0     codetools_0.2-20    cli_3.6.3          
##  [85] geometry_0.4.7      Rdpack_2.6.1        munsell_0.5.1      
##  [88] jquerylib_0.1.4     Rcpp_1.0.12         doSNOW_1.0.20      
##  [91] globals_0.16.3      coda_0.19-4.1       parallel_4.3.2     
##  [94] picante_1.8.2       listenv_0.9.1       viridisLite_0.4.2  
##  [97] mvtnorm_1.3-1       scales_1.3.0        rlang_1.1.4        
## [100] cowplot_1.1.3       fastmatch_1.1-4     waldo_0.5.2

Before submitting

  • Take off the holistic models
  • Update that you took off the third time point
  • Comment code

References

Bates, Douglas, Martin Mächler, Benjamin M. Bolker, and Steven C. Walker. 2015. “Fitting Linear Mixed-Effects Models Using Lme4.” Journal of Statistical Software 67. https://doi.org/10.18637/jss.v067.i01.